re PR c++/775 (2.97 error declaring nested class a friend)
cp: PR c++/775 * cp-tree.h (handle_class_head): Adjust prototype. * decl2.c (handle_class_head): Add DEFN_P and NEW_TYPE_P parameters. Use for all class heads. * parse.y (named_class_head_sans_basetype, named_class_head, named_complex_class_head_sans_basetype, named_class_head_sans_basetype_defn, unnamed_class_head): Remove. (class_head, class_head_apparent_template): Recognize class heads (class_head_decl, class_head_defn): New reductions. Process class heads. (structsp): Adjust class definition and class declaration reductions. (maybe_base_class_list): Give diagnostic on empty list. testsuite: * g++.dg/template/friend2.C: New test. * g++.old-deja/g++/brendan/crash8.C: Adjust location of error. From-SVN: r48466
This commit is contained in:
parent
4542128ef1
commit
d46a33b322
7 changed files with 242 additions and 193 deletions
|
@ -1,3 +1,20 @@
|
|||
2002-01-02 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
PR c++/775
|
||||
* cp-tree.h (handle_class_head): Adjust prototype.
|
||||
* decl2.c (handle_class_head): Add DEFN_P and NEW_TYPE_P
|
||||
parameters. Use for all class heads.
|
||||
* parse.y (named_class_head_sans_basetype, named_class_head,
|
||||
named_complex_class_head_sans_basetype,
|
||||
named_class_head_sans_basetype_defn,
|
||||
unnamed_class_head): Remove.
|
||||
(class_head, class_head_apparent_template): Recognize class heads
|
||||
(class_head_decl, class_head_defn): New reductions. Process class
|
||||
heads.
|
||||
(structsp): Adjust class definition and class declaration
|
||||
reductions.
|
||||
(maybe_base_class_list): Give diagnostic on empty list.
|
||||
|
||||
2002-01-02 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
PR c++/4379
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Definitions for C++ parsing and type checking.
|
||||
Copyright (C) 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
2000, 2001 Free Software Foundation, Inc.
|
||||
2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
Contributed by Michael Tiemann (tiemann@cygnus.com)
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
@ -3769,7 +3769,7 @@ extern tree do_class_using_decl PARAMS ((tree));
|
|||
extern void do_using_directive PARAMS ((tree));
|
||||
extern void check_default_args PARAMS ((tree));
|
||||
extern void mark_used PARAMS ((tree));
|
||||
extern tree handle_class_head PARAMS ((tree, tree, tree));
|
||||
extern tree handle_class_head PARAMS ((tree, tree, tree, int, int *));
|
||||
extern tree lookup_arg_dependent PARAMS ((tree, tree, tree));
|
||||
extern void finish_static_data_member_decl PARAMS ((tree, tree, tree, int));
|
||||
extern tree build_artificial_parm PARAMS ((tree, tree));
|
||||
|
|
126
gcc/cp/decl2.c
126
gcc/cp/decl2.c
|
@ -5162,70 +5162,90 @@ mark_used (decl)
|
|||
instantiate_decl (decl, /*defer_ok=*/1);
|
||||
}
|
||||
|
||||
/* Helper function for named_class_head_sans_basetype nonterminal. We
|
||||
have just seen something of the form `AGGR SCOPE::ID'. Return a
|
||||
TYPE_DECL for the type declared by ID in SCOPE. */
|
||||
/* Helper function for class_head_decl and class_head_defn
|
||||
nonterminals. AGGR is the class, union or struct tag. SCOPE is the
|
||||
explicit scope used (NULL for no scope resolution). ID is the
|
||||
name. DEFN_P is true, if this is a definition of the class and
|
||||
NEW_TYPE_P is set to non-zero, if we push into the scope containing
|
||||
the to be defined aggregate.
|
||||
|
||||
Return a TYPE_DECL for the type declared by ID in SCOPE. */
|
||||
|
||||
tree
|
||||
handle_class_head (aggr, scope, id)
|
||||
handle_class_head (aggr, scope, id, defn_p, new_type_p)
|
||||
tree aggr, scope, id;
|
||||
int defn_p;
|
||||
int *new_type_p;
|
||||
{
|
||||
tree decl = NULL_TREE;
|
||||
|
||||
if (TREE_CODE (id) == TYPE_DECL)
|
||||
/* We must bash typedefs back to the main decl of the type. Otherwise
|
||||
we become confused about scopes. */
|
||||
decl = TYPE_MAIN_DECL (TREE_TYPE (id));
|
||||
else if (DECL_CLASS_TEMPLATE_P (id))
|
||||
decl = DECL_TEMPLATE_RESULT (id);
|
||||
else
|
||||
{
|
||||
tree current = current_scope ();
|
||||
tree current = current_scope ();
|
||||
bool xrefd_p = false;
|
||||
|
||||
if (current == NULL_TREE)
|
||||
current = current_namespace;
|
||||
if (scope == NULL_TREE)
|
||||
scope = global_namespace;
|
||||
if (current == NULL_TREE)
|
||||
current = current_namespace;
|
||||
|
||||
if (TYPE_P (scope))
|
||||
{
|
||||
/* According to the suggested resolution of core issue 180,
|
||||
'typename' is assumed after a class-key. */
|
||||
decl = make_typename_type (scope, id, 1);
|
||||
if (decl != error_mark_node)
|
||||
decl = TYPE_MAIN_DECL (decl);
|
||||
else
|
||||
decl = NULL_TREE;
|
||||
}
|
||||
else if (scope == current)
|
||||
{
|
||||
/* We've been given AGGR SCOPE::ID, when we're already inside SCOPE.
|
||||
Be nice about it. */
|
||||
if (pedantic)
|
||||
pedwarn ("extra qualification `%T::' on member `%D' ignored",
|
||||
FROB_CONTEXT (scope), id);
|
||||
}
|
||||
else if (scope != global_namespace)
|
||||
error ("`%T' does not have a nested type named `%D'", scope, id);
|
||||
*new_type_p = 0;
|
||||
|
||||
if (scope)
|
||||
{
|
||||
if (TREE_CODE (id) == TYPE_DECL)
|
||||
/* We must bash typedefs back to the main decl of the
|
||||
type. Otherwise we become confused about scopes. */
|
||||
decl = TYPE_MAIN_DECL (TREE_TYPE (id));
|
||||
else if (DECL_CLASS_TEMPLATE_P (id))
|
||||
decl = DECL_TEMPLATE_RESULT (id);
|
||||
else
|
||||
error ("no file-scope type named `%D'", id);
|
||||
|
||||
/* Inject it at the current scope. */
|
||||
if (! decl)
|
||||
decl = TYPE_MAIN_DECL (xref_tag (aggr, id, 1));
|
||||
{
|
||||
if (TYPE_P (scope))
|
||||
{
|
||||
/* According to the suggested resolution of core issue
|
||||
180, 'typename' is assumed after a class-key. */
|
||||
decl = make_typename_type (scope, id, 1);
|
||||
if (decl != error_mark_node)
|
||||
decl = TYPE_MAIN_DECL (decl);
|
||||
else
|
||||
decl = NULL_TREE;
|
||||
}
|
||||
else if (scope == current)
|
||||
{
|
||||
/* We've been given AGGR SCOPE::ID, when we're already
|
||||
inside SCOPE. Be nice about it. */
|
||||
if (pedantic)
|
||||
pedwarn ("extra qualification `%T::' on member `%D' ignored",
|
||||
scope, id);
|
||||
}
|
||||
else
|
||||
error ("`%T' does not have a class or union named `%D'",
|
||||
scope, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!decl)
|
||||
{
|
||||
decl = TYPE_MAIN_DECL (xref_tag (aggr, id, !defn_p));
|
||||
xrefd_p = true;
|
||||
}
|
||||
|
||||
/* Enter the SCOPE. If this turns out not to be a definition, the
|
||||
parser must leave the scope. */
|
||||
push_scope (CP_DECL_CONTEXT (decl));
|
||||
|
||||
/* If we see something like:
|
||||
if (!TYPE_BINFO (TREE_TYPE (decl)))
|
||||
{
|
||||
error ("`%T' is not a class or union type", decl);
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (defn_p)
|
||||
{
|
||||
/* For a definition, we want to enter the containing scope
|
||||
before looking up any base classes etc. Only do so, if this
|
||||
is different to the current scope. */
|
||||
tree context = CP_DECL_CONTEXT (decl);
|
||||
|
||||
template <typename T> struct S::I ....
|
||||
|
||||
we must create a TEMPLATE_DECL for the nested type. */
|
||||
if (PROCESSING_REAL_TEMPLATE_DECL_P ())
|
||||
decl = push_template_decl (decl);
|
||||
*new_type_p = current != context;
|
||||
if (*new_type_p)
|
||||
push_scope (context);
|
||||
|
||||
if (!xrefd_p && PROCESSING_REAL_TEMPLATE_DECL_P ())
|
||||
decl = push_template_decl (decl);
|
||||
}
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
|
248
gcc/cp/parse.y
248
gcc/cp/parse.y
|
@ -1,6 +1,6 @@
|
|||
/* YACC parser for C++ syntax.
|
||||
Copyright (C) 1988, 1989, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
Hacked by Michael Tiemann (tiemann@cygnus.com)
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
@ -386,10 +386,8 @@ cp_parse_init ()
|
|||
%type <ttype> component_constructor_declarator
|
||||
%type <ttype> fn.def2 return_id constructor_declarator
|
||||
%type <ttype> .begin_function_body
|
||||
%type <ttype> named_class_head_sans_basetype
|
||||
%type <ftype> class_head named_class_head
|
||||
%type <ftype> named_complex_class_head_sans_basetype
|
||||
%type <ttype> unnamed_class_head
|
||||
%type <ttype> class_head class_head_apparent_template
|
||||
%type <ftype> class_head_decl class_head_defn
|
||||
%type <ttype> base_class_list
|
||||
%type <ttype> base_class_access_list
|
||||
%type <ttype> base_class maybe_base_class_list base_class.1
|
||||
|
@ -418,7 +416,6 @@ cp_parse_init ()
|
|||
%type <ttype> explicit_template_type
|
||||
/* in order to recognize aggr tags as defining and thus shadowing. */
|
||||
%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
|
||||
%type <ttype> named_class_head_sans_basetype_defn
|
||||
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
|
||||
%type <ttype> handler_args
|
||||
%type <ttype> self_template_type .finish_template_type
|
||||
|
@ -2277,8 +2274,21 @@ structsp:
|
|||
if (!processing_template_decl)
|
||||
pedwarn ("using `typename' outside of template"); }
|
||||
/* C++ extensions, merged with C to avoid shift/reduce conflicts */
|
||||
| class_head '{'
|
||||
{ $1.t = begin_class_definition ($1.t);
|
||||
| class_head_defn maybe_base_class_list '{'
|
||||
{
|
||||
if ($2 && $1.t != error_mark_node)
|
||||
{
|
||||
tree type = TREE_TYPE ($1.t);
|
||||
|
||||
if (TREE_CODE (type) == TYPENAME_TYPE)
|
||||
/* In a definition of a member class template,
|
||||
we will get here with an implicit typename,
|
||||
a TYPENAME_TYPE with a type. */
|
||||
type = TREE_TYPE (type);
|
||||
maybe_process_partial_specialization (type);
|
||||
xref_basetypes (current_aggr, $1.t, type, $2);
|
||||
}
|
||||
$1.t = begin_class_definition (TREE_TYPE ($1.t));
|
||||
current_aggr = NULL_TREE; }
|
||||
opt.component_decl_list '}' maybe_attribute
|
||||
{
|
||||
|
@ -2289,8 +2299,7 @@ structsp:
|
|||
yychar = YYLEX;
|
||||
semi = yychar == ';';
|
||||
|
||||
t = finish_class_definition ($1.t, $6, semi,
|
||||
$1.new_type_flag);
|
||||
t = finish_class_definition ($1.t, $7, semi, $1.new_type_flag);
|
||||
$<ttype>$ = t;
|
||||
|
||||
/* restore current_aggr */
|
||||
|
@ -2307,32 +2316,13 @@ structsp:
|
|||
pending_inlines
|
||||
{
|
||||
finish_inline_definitions ();
|
||||
$$.t = $<ttype>7;
|
||||
$$.t = $<ttype>8;
|
||||
$$.new_type_flag = 1;
|
||||
}
|
||||
| class_head %prec EMPTY
|
||||
| class_head_decl
|
||||
{
|
||||
if ($1.new_type_flag && $1.t != error_mark_node)
|
||||
pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL ($1.t)));
|
||||
$$.new_type_flag = 0;
|
||||
if ($1.t == error_mark_node)
|
||||
$$.t = $1.t;
|
||||
else if (TYPE_BINFO ($1.t) == NULL_TREE)
|
||||
{
|
||||
error ("%T is not a class type", $1.t);
|
||||
$$.t = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
$$.t = $1.t;
|
||||
/* struct B: public A; is not accepted by the standard grammar. */
|
||||
if (CLASS_TYPE_P ($$.t)
|
||||
&& TYPE_BINFO_BASETYPES ($$.t)
|
||||
&& !COMPLETE_TYPE_P ($$.t)
|
||||
&& ! TYPE_BEING_DEFINED ($$.t))
|
||||
error ("base clause without member specification for `%#T'",
|
||||
$$.t);
|
||||
}
|
||||
$$.t = TREE_TYPE ($1.t);
|
||||
$$.new_type_flag = $1.new_type_flag;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -2362,140 +2352,126 @@ aggr:
|
|||
{ $$ = build_tree_list ($2, $1); }
|
||||
;
|
||||
|
||||
named_class_head_sans_basetype:
|
||||
class_head:
|
||||
aggr identifier
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
named_class_head_sans_basetype_defn:
|
||||
aggr identifier_defn %prec EMPTY
|
||||
{ current_aggr = $$; $$ = $2; }
|
||||
| named_class_head_sans_basetype '{'
|
||||
{ yyungetc ('{', 1); }
|
||||
| named_class_head_sans_basetype ':'
|
||||
{ yyungetc (':', 1); }
|
||||
;
|
||||
|
||||
named_complex_class_head_sans_basetype:
|
||||
aggr nested_name_specifier identifier
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = handle_class_head ($1, $2, $3);
|
||||
$$.new_type_flag = 1;
|
||||
$$ = build_tree_list (NULL_TREE, $2);
|
||||
}
|
||||
| aggr nested_name_specifier identifier
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$ = build_tree_list ($2, $3);
|
||||
}
|
||||
| aggr global_scope nested_name_specifier identifier
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = handle_class_head ($1, $3, $4);
|
||||
$$.new_type_flag = 1;
|
||||
$$ = build_tree_list ($3, $4);
|
||||
}
|
||||
| aggr global_scope identifier
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = handle_class_head ($1, NULL_TREE, $3);
|
||||
$$.new_type_flag = 1;
|
||||
$$ = build_tree_list (global_namespace, $3);
|
||||
}
|
||||
| aggr apparent_template_type
|
||||
;
|
||||
|
||||
class_head_apparent_template:
|
||||
aggr apparent_template_type
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = $2;
|
||||
$$.new_type_flag = 0;
|
||||
$$ = $2;
|
||||
}
|
||||
| aggr nested_name_specifier apparent_template_type
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = $3;
|
||||
push_scope (CP_DECL_CONTEXT ($$.t));
|
||||
$$.new_type_flag = 1;
|
||||
$$ = $3;
|
||||
}
|
||||
| aggr global_scope nested_name_specifier apparent_template_type
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = $4;
|
||||
push_scope (CP_DECL_CONTEXT ($$.t));
|
||||
$$ = $4;
|
||||
}
|
||||
;
|
||||
|
||||
class_head_decl:
|
||||
class_head %prec EMPTY
|
||||
{
|
||||
$$.t = handle_class_head (current_aggr,
|
||||
TREE_PURPOSE ($1), TREE_VALUE ($1),
|
||||
0, &$$.new_type_flag);
|
||||
}
|
||||
| aggr identifier_defn %prec EMPTY
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = TYPE_MAIN_DECL (xref_tag (current_aggr, $2, 0));
|
||||
$$.new_type_flag = 1;
|
||||
}
|
||||
;
|
||||
|
||||
named_class_head:
|
||||
named_class_head_sans_basetype %prec EMPTY
|
||||
{
|
||||
$$.t = xref_tag (current_aggr, $1, 1);
|
||||
$$.new_type_flag = 0;
|
||||
}
|
||||
| named_class_head_sans_basetype_defn
|
||||
{ $<ttype>$ = xref_tag (current_aggr, $1, 0); }
|
||||
/* Class name is unqualified, so we look for base classes
|
||||
in the current scope. */
|
||||
maybe_base_class_list %prec EMPTY
|
||||
{
|
||||
$$.t = $<ttype>2;
|
||||
$$.new_type_flag = 0;
|
||||
if ($3)
|
||||
xref_basetypes (current_aggr, $1, $<ttype>2, $3);
|
||||
}
|
||||
| named_complex_class_head_sans_basetype
|
||||
maybe_base_class_list
|
||||
{
|
||||
if ($1.t != error_mark_node)
|
||||
{
|
||||
tree type = TREE_TYPE ($1.t);
|
||||
|
||||
$$.t = type;
|
||||
$$.new_type_flag = $1.new_type_flag;
|
||||
if ((current_aggr == union_type_node)
|
||||
!= (TREE_CODE (type) == UNION_TYPE))
|
||||
pedwarn (current_aggr == union_type_node
|
||||
? "`union' tag used in declaring `%#T'"
|
||||
: "non-`union' tag used in declaring `%#T'",
|
||||
type);
|
||||
else if (TREE_CODE (type) == RECORD_TYPE)
|
||||
/* We might be specializing a template with a different
|
||||
class-key; deal. */
|
||||
CLASSTYPE_DECLARED_CLASS (type)
|
||||
= (current_aggr == class_type_node);
|
||||
if ($2)
|
||||
{
|
||||
if (TREE_CODE (type) == TYPENAME_TYPE)
|
||||
/* In a definition of a member class template, we
|
||||
will get here with an implicit typename, a
|
||||
TYPENAME_TYPE with a type. */
|
||||
type = TREE_TYPE (type);
|
||||
maybe_process_partial_specialization (type);
|
||||
xref_basetypes (current_aggr, $1.t, type, $2);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
unnamed_class_head:
|
||||
aggr '{'
|
||||
{ $$ = xref_tag ($$, make_anon_name (), 0);
|
||||
yyungetc ('{', 1); }
|
||||
;
|
||||
|
||||
/* The tree output of this nonterminal a declarationf or the type
|
||||
named. If NEW_TYPE_FLAG is set, then the name used in this
|
||||
class-head was explicitly qualified, e.g.: `struct X::Y'. We have
|
||||
already called push_scope for X. */
|
||||
class_head:
|
||||
unnamed_class_head
|
||||
{
|
||||
| class_head_apparent_template %prec EMPTY
|
||||
{
|
||||
$$.t = $1;
|
||||
$$.new_type_flag = 0;
|
||||
}
|
||||
| named_class_head
|
||||
;
|
||||
|
||||
class_head_defn:
|
||||
class_head '{'
|
||||
{
|
||||
yyungetc ('{', 1);
|
||||
$$.t = handle_class_head (current_aggr,
|
||||
TREE_PURPOSE ($1), TREE_VALUE ($1),
|
||||
1, &$$.new_type_flag);
|
||||
}
|
||||
| class_head ':'
|
||||
{
|
||||
yyungetc (':', 1);
|
||||
$$.t = handle_class_head (current_aggr,
|
||||
TREE_PURPOSE ($1), TREE_VALUE ($1),
|
||||
1, &$$.new_type_flag);
|
||||
}
|
||||
| class_head_apparent_template '{'
|
||||
{
|
||||
yyungetc ('{', 1);
|
||||
$$.t = $1;
|
||||
$$.new_type_flag = 0;
|
||||
}
|
||||
| class_head_apparent_template ':'
|
||||
{
|
||||
yyungetc (':', 1);
|
||||
$$.t = $1;
|
||||
$$.new_type_flag = 0;
|
||||
}
|
||||
| aggr identifier_defn '{'
|
||||
{
|
||||
yyungetc ('{', 1);
|
||||
current_aggr = $1;
|
||||
$$.t = handle_class_head (current_aggr,
|
||||
NULL_TREE, $2,
|
||||
1, &$$.new_type_flag);
|
||||
}
|
||||
| aggr identifier_defn ':'
|
||||
{
|
||||
yyungetc (':', 1);
|
||||
current_aggr = $1;
|
||||
$$.t = handle_class_head (current_aggr,
|
||||
NULL_TREE, $2,
|
||||
1, &$$.new_type_flag);
|
||||
}
|
||||
| aggr '{'
|
||||
{
|
||||
current_aggr = $1;
|
||||
$$.t = TYPE_MAIN_DECL (xref_tag ($1, make_anon_name (), 0));
|
||||
$$.new_type_flag = 0;
|
||||
yyungetc ('{', 1);
|
||||
}
|
||||
;
|
||||
|
||||
maybe_base_class_list:
|
||||
/* empty */ %prec EMPTY
|
||||
/* empty */
|
||||
{ $$ = NULL_TREE; }
|
||||
| ':' see_typename %prec EMPTY
|
||||
{ yyungetc(':', 1); $$ = NULL_TREE; }
|
||||
| ':' see_typename base_class_list %prec EMPTY
|
||||
| ':' see_typename
|
||||
{ error ("no bases given following `:'");
|
||||
$$ = NULL_TREE; }
|
||||
| ':' see_typename base_class_list
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2002-01-02 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/template/friend2.C: New test.
|
||||
* g++.old-deja/g++/brendan/crash8.C: Adjust location of error.
|
||||
|
||||
2002-01-02 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/other/ptrmem1.C: New test.
|
||||
|
|
31
gcc/testsuite/g++.dg/template/friend3.C
Normal file
31
gcc/testsuite/g++.dg/template/friend3.C
Normal file
|
@ -0,0 +1,31 @@
|
|||
// { dg-do compile }
|
||||
|
||||
// Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
// Contributed by Nathan Sidwell 28 Dec 2001 <nathan@codesourcery.com>
|
||||
|
||||
// PR 775 friend classes with qualified names inside template classes.
|
||||
|
||||
struct A
|
||||
{
|
||||
struct B {
|
||||
B () { }
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct C: A {
|
||||
friend A::B::B (); // 2.95.2 ICE
|
||||
friend struct A;
|
||||
friend struct A::B; // 2.97 error
|
||||
};
|
||||
|
||||
template class C<char>;
|
||||
|
||||
template <typename T> class TPL
|
||||
{
|
||||
class nested;
|
||||
};
|
||||
|
||||
template <typename T> class TPL<T>::nested
|
||||
{
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
// Build don't link:
|
||||
// GROUPS passed old-abort
|
||||
template<int a, int b>
|
||||
class Elvis // ERROR - in template.*
|
||||
{
|
||||
class Elvis
|
||||
{ // ERROR - in template.*
|
||||
} ;
|
||||
|
||||
template<int a>
|
||||
|
|
Loading…
Add table
Reference in a new issue