re PR c++/9128 (Typeid does not work on polymorphic classes)

PR c++/9128
	* g++.dg/rtti/typeid1.C: New file.

	PR c++/9153
	* g++.dg/parse/lookup1.C: New file.

	PR c++/9171
	* g++.dg/templ/spec5.C: New file.

	* cp-tree.h (reparse_absdcl_as_expr): Remove.
	(reparse_absdcl_as_casts): Likewise.
	(reparse_decl_as_expr): Likewise.
	(finish_decl_parsing): Likewise.
	* decl2.c (reparse_absdcl_as_expr): Remove.
	(reparse_absdcl_as_casts): Likewise.
	(repase_decl_as_expr): Likewise.
	(finish_decl_parsing): Likewise.

	PR c++/9128
	PR c++/9153
	PR c++/9171
	* parser.c (cp_parser_pre_parsed_nested_name_specifier): New
	function.
	(cp_parser_nested_name_specifier_opt): Correct the
	check_dependency_p false.
	(cp_parser_postfix_expression): Fix formatting.
	(cp_parser_decl_specifier_seq): Avoid looking for constructor
	declarators when possible.
	(cp_parser_template_id): Avoid performing name-lookup when
	possible.
	(cp_parser_class_head): Do not count specializations when counting
	levels of templates.
	(cp_parser_constructor_declarator_p): Return immediately if
	there's no chance that the tokens form a constructor declarator.
	* rtti.c (throw_bad_typeid): Add comment.  Do not return an
	expression with reference type.
	(get_tinfo_decl_dynamic): Do not return an expression with
	reference type.
	(build_typeid): Add comment.  Do not return an expression with
	reference type.
	* typeck.c (build_class_member_access_expr): Improve handling of
	conditionals and comma-expressions as objects.

From-SVN: r61166
This commit is contained in:
Mark Mitchell 2003-01-10 20:30:56 +00:00 committed by Mark Mitchell
parent 0cdca92b46
commit 2050a1bbac
10 changed files with 208 additions and 212 deletions

View File

@ -1,3 +1,39 @@
2003-01-10 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (reparse_absdcl_as_expr): Remove.
(reparse_absdcl_as_casts): Likewise.
(reparse_decl_as_expr): Likewise.
(finish_decl_parsing): Likewise.
* decl2.c (reparse_absdcl_as_expr): Remove.
(reparse_absdcl_as_casts): Likewise.
(repase_decl_as_expr): Likewise.
(finish_decl_parsing): Likewise.
PR c++/9128
PR c++/9153
PR c++/9171
* parser.c (cp_parser_pre_parsed_nested_name_specifier): New
function.
(cp_parser_nested_name_specifier_opt): Correct the
check_dependency_p false.
(cp_parser_postfix_expression): Fix formatting.
(cp_parser_decl_specifier_seq): Avoid looking for constructor
declarators when possible.
(cp_parser_template_id): Avoid performing name-lookup when
possible.
(cp_parser_class_head): Do not count specializations when counting
levels of templates.
(cp_parser_constructor_declarator_p): Return immediately if
there's no chance that the tokens form a constructor declarator.
* rtti.c (throw_bad_typeid): Add comment. Do not return an
expression with reference type.
(get_tinfo_decl_dynamic): Do not return an expression with
reference type.
(build_typeid): Add comment. Do not return an expression with
reference type.
* typeck.c (build_class_member_access_expr): Improve handling of
conditionals and comma-expressions as objects.
2003-01-09 Nathanael Nerode <neroden@gcc.gnu.org>
* decl.c (bad_specifiers): Fix parameter order error I introduced.

View File

@ -3865,13 +3865,9 @@ extern void import_export_decl (tree);
extern void import_export_tinfo (tree, tree, bool);
extern tree build_cleanup PARAMS ((tree));
extern void finish_file PARAMS ((void));
extern tree reparse_absdcl_as_expr PARAMS ((tree, tree));
extern tree reparse_absdcl_as_casts PARAMS ((tree, tree));
extern tree build_expr_from_tree PARAMS ((tree));
extern tree build_offset_ref_call_from_tree (tree, tree);
extern tree build_call_from_tree (tree, tree, bool);
extern tree reparse_decl_as_expr (tree, tree);
extern tree finish_decl_parsing (tree);
extern void set_decl_namespace (tree, tree, bool);
extern tree current_decl_namespace PARAMS ((void));
extern void push_decl_namespace PARAMS ((tree));

View File

@ -2876,79 +2876,6 @@ finish_file ()
}
}
/* This is something of the form 'A()()()()()+1' that has turned out to be an
expr. Since it was parsed like a type, we need to wade through and fix
that. Unfortunately, since operator() is left-associative, we can't use
tail recursion. In the above example, TYPE is `A', and DECL is
`()()()()()'.
Maybe this shouldn't be recursive, but how often will it actually be
used? (jason) */
tree
reparse_absdcl_as_expr (type, decl)
tree type, decl;
{
/* do build_functional_cast (type, NULL_TREE) at bottom */
if (TREE_OPERAND (decl, 0) == NULL_TREE)
return build_functional_cast (type, NULL_TREE);
/* recurse */
decl = reparse_absdcl_as_expr (type, TREE_OPERAND (decl, 0));
return finish_call_expr (decl, NULL_TREE, /*disallow_virtual=*/false);
}
/* This is something of the form `int ((int)(int)(int)1)' that has turned
out to be an expr. Since it was parsed like a type, we need to wade
through and fix that. Since casts are right-associative, we are
reversing the order, so we don't have to recurse.
In the above example, DECL is the `(int)(int)(int)', and EXPR is the
`1'. */
tree
reparse_absdcl_as_casts (decl, expr)
tree decl, expr;
{
tree type;
int non_void_p = 0;
if (TREE_CODE (expr) == CONSTRUCTOR
&& TREE_TYPE (expr) == 0)
{
type = groktypename (TREE_VALUE (CALL_DECLARATOR_PARMS (decl)));
decl = TREE_OPERAND (decl, 0);
if (processing_template_decl)
TREE_TYPE (expr) = type;
else
{
expr = digest_init (type, expr, (tree *) 0);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
int failure = complete_array_type (type, expr, 1);
my_friendly_assert (!failure, 78);
}
}
}
while (decl)
{
type = groktypename (TREE_VALUE (CALL_DECLARATOR_PARMS (decl)));
decl = TREE_OPERAND (decl, 0);
if (!VOID_TYPE_P (type))
non_void_p = 1;
expr = build_c_cast (type, expr);
}
if (warn_old_style_cast && ! in_system_header
&& non_void_p && current_lang_name != lang_name_c)
warning ("use of old-style cast");
return expr;
}
/* T is the parse tree for an expression. Return the expression after
performing semantic analysis. */
@ -3461,62 +3388,6 @@ build_call_from_tree (tree fn, tree args, bool disallow_virtual)
return finish_call_expr (fn, args, disallow_virtual);
}
/* This is something of the form `int (*a)++' that has turned out to be an
expr. It was only converted into parse nodes, so we need to go through
and build up the semantics. Most of the work is done by
build_expr_from_tree, above.
In the above example, TYPE is `int' and DECL is `*a'. */
tree
reparse_decl_as_expr (tree type, tree decl)
{
decl = build_expr_from_tree (decl);
if (type)
return build_functional_cast (type, build_tree_list (NULL_TREE, decl));
else
return decl;
}
/* This is something of the form `int (*a)' that has turned out to be a
decl. It was only converted into parse nodes, so we need to do the
checking that make_{pointer,reference}_declarator do. */
tree
finish_decl_parsing (tree decl)
{
switch (TREE_CODE (decl))
{
case IDENTIFIER_NODE:
return decl;
case INDIRECT_REF:
return make_pointer_declarator
(NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0)));
case ADDR_EXPR:
return make_reference_declarator
(NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0)));
case BIT_NOT_EXPR:
TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0));
return decl;
case SCOPE_REF:
push_nested_class (TREE_TYPE (TREE_OPERAND (decl, 0)), 3);
TREE_COMPLEXITY (decl) = current_class_depth;
return decl;
case ARRAY_REF:
TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0));
return decl;
case TREE_LIST:
/* For attribute handling. */
TREE_VALUE (decl) = finish_decl_parsing (TREE_VALUE (decl));
return decl;
case TEMPLATE_ID_EXPR:
return decl;
default:
abort ();
return NULL_TREE;
}
}
/* Return 1 if root encloses child. */
static bool

View File

@ -1764,6 +1764,8 @@ static void cp_parser_check_class_key
(enum tag_types, tree type);
static bool cp_parser_optional_template_keyword
(cp_parser *);
static void cp_parser_pre_parsed_nested_name_specifier
(cp_parser *);
static void cp_parser_cache_group
(cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned);
static void cp_parser_parse_tentatively
@ -3091,15 +3093,6 @@ cp_parser_primary_expression (cp_parser *parser,
function does not do this in order to avoid wastefully creating
SCOPE_REFs when they are not required.
If ASSUME_TYPENAME_P is true then we assume that qualified names
are typenames. This flag is set when parsing a declarator-id;
for something like:
template <class T>
int S<T>::R::i = 3;
we are supposed to assume that `S<T>::R' is a class.
If TEMPLATE_KEYWORD_P is true, then we have just seen the
`template' keyword.
@ -3460,25 +3453,19 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool success = false;
tree access_check = NULL_TREE;
ptrdiff_t start;
cp_token* token;
/* If the next token corresponds to a nested name specifier, there
is no need to reparse it. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
is no need to reparse it. However, if CHECK_DEPENDENCY_P is
false, it may have been true before, in which case something
like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
CHECK_DEPENDENCY_P is false, we have to fall through into the
main loop. */
if (check_dependency_p
&& cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
{
tree value;
tree check;
/* Get the stored value. */
value = cp_lexer_consume_token (parser->lexer)->value;
/* Perform any access checks that were deferred. */
for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
cp_parser_defer_access_check (parser,
TREE_PURPOSE (check),
TREE_VALUE (check));
/* Set the scope from the stored value. */
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
parser->object_scope = NULL_TREE;
cp_parser_pre_parsed_nested_name_specifier (parser);
return parser->scope;
}
@ -3486,10 +3473,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
cp_token *next_token = cp_lexer_peek_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
next_token);
token);
access_check = parser->context->deferred_access_checks;
}
else
@ -3500,13 +3487,25 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
tree new_scope;
tree old_scope;
tree saved_qualifying_scope;
cp_token *token;
bool template_keyword_p;
/* Spot cases that cannot be the beginning of a
nested-name-specifier. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is CPP_NESTED_NAME_SPECIFIER, just process
the already parsed nested-name-specifier. */
if (token->type == CPP_NESTED_NAME_SPECIFIER)
{
/* Grab the nested-name-specifier and continue the loop. */
cp_parser_pre_parsed_nested_name_specifier (parser);
success = true;
continue;
}
/* Spot cases that cannot be the beginning of a
nested-name-specifier. On the second and subsequent times
through the loop, we look for the `template' keyword. */
token = cp_lexer_peek_token (parser->lexer);
if (success && token->keyword == RID_TEMPLATE)
;
/* A template-id can start a nested-name-specifier. */
@ -3631,7 +3630,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
we issue duplicate error messages. */
if (success && start >= 0)
{
cp_token *token;
tree c;
/* Find the token that corresponds to the start of the
@ -4232,20 +4230,16 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, args));
else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
{
/* A call to a static class member, or a
namespace-scope function. */
postfix_expression
= finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/true);
}
/* A call to a static class member, or a namespace-scope
function. */
postfix_expression
= finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/true);
else
{
/* All other function calls. */
postfix_expression
= finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/false);
}
/* All other function calls. */
postfix_expression
= finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/false);
/* The POSTFIX_EXPRESSION is certainly no longer an id. */
idk = CP_PARSER_ID_KIND_NONE;
@ -6903,6 +6897,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
{
tree decl_specs = NULL_TREE;
bool friend_p = false;
bool constructor_possible_p = true;
/* Assume no class or enumeration type is declared. */
*declares_class_or_enum = false;
@ -6961,6 +6956,8 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
decl_spec = token->value;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
/* A constructor declarator cannot appear in a typedef. */
constructor_possible_p = false;
break;
/* storage-class-specifier:
@ -6988,6 +6985,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
/* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */
constructor_p = (!decl_spec
&& constructor_possible_p
&& cp_parser_constructor_declarator_p (parser,
friend_p));
@ -7045,6 +7043,9 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
error message later. */
if (decl_spec && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
/* A constructor declarator cannot follow a type-specifier. */
if (decl_spec)
constructor_possible_p = false;
}
/* If we still do not have a DECL_SPEC, then there are no more
@ -8102,10 +8103,12 @@ cp_parser_template_id (cp_parser *parser,
bool saved_greater_than_is_operator_p;
ptrdiff_t start_of_id;
tree access_check = NULL_TREE;
cp_token *next_token;
/* If the next token corresponds to a template-id, there is no need
to reparse it. */
if (cp_lexer_next_token_is (parser->lexer, CPP_TEMPLATE_ID))
next_token = cp_lexer_peek_token (parser->lexer);
if (next_token->type == CPP_TEMPLATE_ID)
{
tree value;
tree check;
@ -8121,11 +8124,21 @@ cp_parser_template_id (cp_parser *parser,
return TREE_VALUE (value);
}
/* Avoid performing name lookup if there is no possibility of
finding a template-id. */
if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR)
|| (next_token->type == CPP_NAME
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS))
{
cp_parser_error (parser, "expected template-id");
return error_mark_node;
}
/* Remember where the template-id starts. */
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
cp_token *next_token = cp_lexer_peek_token (parser->lexer);
next_token = cp_lexer_peek_token (parser->lexer);
start_of_id = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
next_token);
@ -10177,7 +10190,7 @@ cp_parser_direct_declarator (parser, dcl_kind, ctor_dtor_or_conv_p)
{
/* This is either a parameter-declaration-clause, or a
parenthesized declarator. When we know we are parsing a
named declaratory, it must be a paranthesized declarator
named declarator, it must be a paranthesized declarator
if FIRST is true. For instance, `(int)' is a
parameter-declaration-clause, with an omitted
direct-abstract-declarator. But `((*))', is a
@ -11851,7 +11864,7 @@ cp_parser_class_head (parser,
Handle this gracefully by accepting the extra qualifier, and then
issuing an error about it later if this really is a
class-header. If it turns out just to be an elaborated type
class-head. If it turns out just to be an elaborated type
specifier, remain silent. */
if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false))
qualified_p = true;
@ -11920,7 +11933,8 @@ cp_parser_class_head (parser,
if (TYPE_P (scope)
&& CLASS_TYPE_P (scope)
&& CLASSTYPE_TEMPLATE_INFO (scope)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (scope))
++num_templates;
}
}
@ -13983,6 +13997,16 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
bool constructor_p;
tree type_decl = NULL_TREE;
bool nested_name_p;
cp_token *next_token;
/* The common case is that this is not a constructor declarator, so
try to avoid doing lots of work if at all possible. */
next_token = cp_lexer_peek_token (parser->lexer);
if (next_token->type != CPP_NAME
&& next_token->type != CPP_SCOPE
&& next_token->type != CPP_NESTED_NAME_SPECIFIER
&& next_token->type != CPP_TEMPLATE_ID)
return false;
/* Parse tentatively; we are going to roll back all of the tokens
consumed here. */
@ -14830,6 +14854,28 @@ cp_parser_optional_template_keyword (cp_parser *parser)
return false;
}
/* The next token is a CPP_NESTED_NAME_SPECIFIER. Consume the token,
set PARSER->SCOPE, and perform other related actions. */
static void
cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
{
tree value;
tree check;
/* Get the stored value. */
value = cp_lexer_consume_token (parser->lexer)->value;
/* Perform any access checks that were deferred. */
for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
cp_parser_defer_access_check (parser,
TREE_PURPOSE (check),
TREE_VALUE (check));
/* Set the scope from the stored value. */
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
parser->object_scope = NULL_TREE;
}
/* Add tokens to CACHE until an non-nested END token appears. */
static void

View File

@ -174,6 +174,9 @@ throw_bad_cast (void)
return build_call (fn, NULL_TREE);
}
/* Return an expression for "__cxa_bad_typeid()". The expression
returned is an lvalue of type "const std::type_info". */
static tree
throw_bad_typeid (void)
{
@ -187,17 +190,19 @@ throw_bad_typeid (void)
fn = push_throw_library_fn (fn, t);
}
return build_call (fn, NULL_TREE);
return convert_from_reference (build_call (fn, NULL_TREE));
}
/* Return a pointer to type_info function associated with the expression EXP.
If EXP is a reference to a polymorphic class, return the dynamic type;
/* Return an lvalue expression whose type is "const std::type_info"
and whose value indicates the type of the expression EXP. If EXP
is a reference to a polymorphic class, return the dynamic type;
otherwise return the static type of the expression. */
static tree
get_tinfo_decl_dynamic (tree exp)
{
tree type;
tree t;
if (exp == error_mark_node)
return error_mark_node;
@ -221,18 +226,18 @@ get_tinfo_decl_dynamic (tree exp)
if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
{
/* build reference to type_info from vtable. */
tree t;
tree index;
/* The RTTI information is at index -1. */
index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
t = build_vtbl_ref (exp, index);
TREE_TYPE (t) = type_info_ptr_type;
return t;
}
else
/* Otherwise return the type_info for the static type of the expr. */
t = get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
/* Otherwise return the type_info for the static type of the expr. */
return get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
return build_indirect_ref (t, NULL);
}
static bool
@ -253,6 +258,9 @@ typeid_ok_p (void)
return true;
}
/* Return an expression for "typeid(EXP)". The expression returned is
an lvalue of type "const std::type_info". */
tree
build_typeid (tree exp)
{
@ -280,8 +288,6 @@ build_typeid (tree exp)
if (exp == error_mark_node)
return error_mark_node;
exp = build_indirect_ref (exp, NULL);
if (cond)
{
tree bad = throw_bad_typeid ();
@ -289,7 +295,7 @@ build_typeid (tree exp)
exp = build (COND_EXPR, TREE_TYPE (exp), cond, exp, bad);
}
return convert_from_reference (exp);
return exp;
}
/* Generate the NTBS name of a type. */

View File

@ -1865,27 +1865,6 @@ build_class_member_access_expr (tree object, tree member,
my_friendly_assert (DECL_P (member) || BASELINK_P (member),
20020801);
/* Transform `(a, b).x' into `a, b.x' and `(a ? b : c).x' into
`a ? b.x : c.x'. These transformations should not really be
necessary, but they are. */
if (TREE_CODE (object) == COMPOUND_EXPR)
{
result = build_class_member_access_expr (TREE_OPERAND (object, 1),
member, access_path,
preserve_reference);
return build (COMPOUND_EXPR, TREE_TYPE (result),
TREE_OPERAND (object, 0), result);
}
else if (TREE_CODE (object) == COND_EXPR)
return (build_conditional_expr
(TREE_OPERAND (object, 0),
build_class_member_access_expr (TREE_OPERAND (object, 1),
member, access_path,
preserve_reference),
build_class_member_access_expr (TREE_OPERAND (object, 2),
member, access_path,
preserve_reference)));
/* [expr.ref]
The type of the first expression shall be "class object" (of a
@ -1925,6 +1904,34 @@ build_class_member_access_expr (tree object, tree member,
return error_mark_node;
}
/* Transform `(a, b).x' into `(*(a, &b)).x' and `(a ? b : c).x' into
`(*(a ? &b : &c)).x'. Unfortunately, expand_expr cannot handle a
COMPONENT_REF where the first operand is a conditional or comma
expression with class type. */
if (TREE_CODE (object) == COMPOUND_EXPR)
{
object = build (COMPOUND_EXPR,
build_pointer_type (object_type),
TREE_OPERAND (object, 0),
build_unary_op (ADDR_EXPR,
TREE_OPERAND (object, 1),
/*noconvert=*/1));
object = build_indirect_ref (object, NULL);
}
else if (TREE_CODE (object) == COND_EXPR)
{
object = build (COND_EXPR,
build_pointer_type (object_type),
TREE_OPERAND (object, 0),
build_unary_op (ADDR_EXPR,
TREE_OPERAND (object, 1),
/*noconvert=*/1),
build_unary_op (ADDR_EXPR,
TREE_OPERAND (object, 2),
/*noconvert=*/1));
object = build_indirect_ref (object, NULL);
}
/* In [expr.ref], there is an explicit list of the valid choices for
MEMBER. We check for each of those cases here. */
if (TREE_CODE (member) == VAR_DECL)

View File

@ -1,3 +1,14 @@
2003-01-10 Mark Mitchell <mark@codesourcery.com>
PR c++/9128
* g++.dg/rtti/typeid1.C: New file.
PR c++/9153
* g++.dg/parse/lookup1.C: New file.
PR c++/9171
* g++.dg/templ/spec5.C: New file.
2003-01-10 Josef Zlomek <zlomekj@suse.cz>
* gcc.c-torture/compile/20030110-1.c: New test.

View File

@ -0,0 +1,9 @@
#include <list>
using namespace std;
template <class T, class Alloc>
class new_list : public list<T, Alloc> {
public:
typedef typename list<T, Alloc>::iterator iterator;
};

View File

@ -0,0 +1,11 @@
#include <typeinfo>
struct A {
virtual ~A() {}
};
int main() {
A* a = new A;
typeid(*a).name();
}

View File

@ -0,0 +1,3 @@
template <int i> struct A;
template <> struct A<0> { struct B; };
struct A<0>::B {};