Commit 2050a1bb by Mark Mitchell Committed by Mark Mitchell

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
parent 0cdca92b
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> 2003-01-09 Nathanael Nerode <neroden@gcc.gnu.org>
* decl.c (bad_specifiers): Fix parameter order error I introduced. * decl.c (bad_specifiers): Fix parameter order error I introduced.
......
...@@ -3865,13 +3865,9 @@ extern void import_export_decl (tree); ...@@ -3865,13 +3865,9 @@ extern void import_export_decl (tree);
extern void import_export_tinfo (tree, tree, bool); extern void import_export_tinfo (tree, tree, bool);
extern tree build_cleanup PARAMS ((tree)); extern tree build_cleanup PARAMS ((tree));
extern void finish_file PARAMS ((void)); 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_expr_from_tree PARAMS ((tree));
extern tree build_offset_ref_call_from_tree (tree, tree); extern tree build_offset_ref_call_from_tree (tree, tree);
extern tree build_call_from_tree (tree, tree, bool); 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 void set_decl_namespace (tree, tree, bool);
extern tree current_decl_namespace PARAMS ((void)); extern tree current_decl_namespace PARAMS ((void));
extern void push_decl_namespace PARAMS ((tree)); extern void push_decl_namespace PARAMS ((tree));
......
...@@ -2876,79 +2876,6 @@ finish_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 /* T is the parse tree for an expression. Return the expression after
performing semantic analysis. */ performing semantic analysis. */
...@@ -3461,62 +3388,6 @@ build_call_from_tree (tree fn, tree args, bool disallow_virtual) ...@@ -3461,62 +3388,6 @@ build_call_from_tree (tree fn, tree args, bool disallow_virtual)
return finish_call_expr (fn, args, 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. */ /* Return 1 if root encloses child. */
static bool static bool
......
...@@ -1764,6 +1764,8 @@ static void cp_parser_check_class_key ...@@ -1764,6 +1764,8 @@ static void cp_parser_check_class_key
(enum tag_types, tree type); (enum tag_types, tree type);
static bool cp_parser_optional_template_keyword static bool cp_parser_optional_template_keyword
(cp_parser *); (cp_parser *);
static void cp_parser_pre_parsed_nested_name_specifier
(cp_parser *);
static void cp_parser_cache_group static void cp_parser_cache_group
(cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned); (cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned);
static void cp_parser_parse_tentatively static void cp_parser_parse_tentatively
...@@ -3091,15 +3093,6 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -3091,15 +3093,6 @@ cp_parser_primary_expression (cp_parser *parser,
function does not do this in order to avoid wastefully creating function does not do this in order to avoid wastefully creating
SCOPE_REFs when they are not required. 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 If TEMPLATE_KEYWORD_P is true, then we have just seen the
`template' keyword. `template' keyword.
...@@ -3460,25 +3453,19 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, ...@@ -3460,25 +3453,19 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool success = false; bool success = false;
tree access_check = NULL_TREE; tree access_check = NULL_TREE;
ptrdiff_t start; ptrdiff_t start;
cp_token* token;
/* If the next token corresponds to a nested name specifier, there /* If the next token corresponds to a nested name specifier, there
is no need to reparse it. */ is no need to reparse it. However, if CHECK_DEPENDENCY_P is
if (cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER)) 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
tree value; of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
tree check; CHECK_DEPENDENCY_P is false, we have to fall through into the
main loop. */
/* Get the stored value. */ if (check_dependency_p
value = cp_lexer_consume_token (parser->lexer)->value; && cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
/* Perform any access checks that were deferred. */ {
for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check)) cp_parser_pre_parsed_nested_name_specifier (parser);
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;
return parser->scope; return parser->scope;
} }
...@@ -3486,10 +3473,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, ...@@ -3486,10 +3473,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
if (cp_parser_parsing_tentatively (parser) if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (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, start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token, parser->lexer->first_token,
next_token); token);
access_check = parser->context->deferred_access_checks; access_check = parser->context->deferred_access_checks;
} }
else else
...@@ -3500,13 +3487,25 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, ...@@ -3500,13 +3487,25 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
tree new_scope; tree new_scope;
tree old_scope; tree old_scope;
tree saved_qualifying_scope; tree saved_qualifying_scope;
cp_token *token;
bool template_keyword_p; bool template_keyword_p;
/* Spot cases that cannot be the beginning of a /* 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 nested-name-specifier. On the second and subsequent times
through the loop, we look for the `template' keyword. */ through the loop, we look for the `template' keyword. */
token = cp_lexer_peek_token (parser->lexer);
if (success && token->keyword == RID_TEMPLATE) if (success && token->keyword == RID_TEMPLATE)
; ;
/* A template-id can start a nested-name-specifier. */ /* A template-id can start a nested-name-specifier. */
...@@ -3631,7 +3630,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, ...@@ -3631,7 +3630,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
we issue duplicate error messages. */ we issue duplicate error messages. */
if (success && start >= 0) if (success && start >= 0)
{ {
cp_token *token;
tree c; tree c;
/* Find the token that corresponds to the start of the /* Find the token that corresponds to the start of the
...@@ -4232,20 +4230,16 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) ...@@ -4232,20 +4230,16 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
postfix_expression = (build_offset_ref_call_from_tree postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, args)); (postfix_expression, args));
else if (idk == CP_PARSER_ID_KIND_QUALIFIED) else if (idk == CP_PARSER_ID_KIND_QUALIFIED)
{ /* A call to a static class member, or a namespace-scope
/* A call to a static class member, or a function. */
namespace-scope function. */
postfix_expression postfix_expression
= finish_call_expr (postfix_expression, args, = finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/true); /*disallow_virtual=*/true);
}
else else
{
/* All other function calls. */ /* All other function calls. */
postfix_expression postfix_expression
= finish_call_expr (postfix_expression, args, = finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/false); /*disallow_virtual=*/false);
}
/* The POSTFIX_EXPRESSION is certainly no longer an id. */ /* The POSTFIX_EXPRESSION is certainly no longer an id. */
idk = CP_PARSER_ID_KIND_NONE; idk = CP_PARSER_ID_KIND_NONE;
...@@ -6903,6 +6897,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, ...@@ -6903,6 +6897,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
{ {
tree decl_specs = NULL_TREE; tree decl_specs = NULL_TREE;
bool friend_p = false; bool friend_p = false;
bool constructor_possible_p = true;
/* Assume no class or enumeration type is declared. */ /* Assume no class or enumeration type is declared. */
*declares_class_or_enum = false; *declares_class_or_enum = false;
...@@ -6961,6 +6956,8 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, ...@@ -6961,6 +6956,8 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
decl_spec = token->value; decl_spec = token->value;
/* Consume the token. */ /* Consume the token. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
/* A constructor declarator cannot appear in a typedef. */
constructor_possible_p = false;
break; break;
/* storage-class-specifier: /* storage-class-specifier:
...@@ -6988,6 +6985,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, ...@@ -6988,6 +6985,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
/* Constructors are a special case. The `S' in `S()' is not a /* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */ decl-specifier; it is the beginning of the declarator. */
constructor_p = (!decl_spec constructor_p = (!decl_spec
&& constructor_possible_p
&& cp_parser_constructor_declarator_p (parser, && cp_parser_constructor_declarator_p (parser,
friend_p)); friend_p));
...@@ -7045,6 +7043,9 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, ...@@ -7045,6 +7043,9 @@ cp_parser_decl_specifier_seq (parser, flags, attributes,
error message later. */ error message later. */
if (decl_spec && !is_cv_qualifier) if (decl_spec && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; 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 /* 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, ...@@ -8102,10 +8103,12 @@ cp_parser_template_id (cp_parser *parser,
bool saved_greater_than_is_operator_p; bool saved_greater_than_is_operator_p;
ptrdiff_t start_of_id; ptrdiff_t start_of_id;
tree access_check = NULL_TREE; tree access_check = NULL_TREE;
cp_token *next_token;
/* If the next token corresponds to a template-id, there is no need /* If the next token corresponds to a template-id, there is no need
to reparse it. */ 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 value;
tree check; tree check;
...@@ -8121,11 +8124,21 @@ cp_parser_template_id (cp_parser *parser, ...@@ -8121,11 +8124,21 @@ cp_parser_template_id (cp_parser *parser,
return TREE_VALUE (value); 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. */ /* Remember where the template-id starts. */
if (cp_parser_parsing_tentatively (parser) if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (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, start_of_id = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token, parser->lexer->first_token,
next_token); next_token);
...@@ -10177,7 +10190,7 @@ cp_parser_direct_declarator (parser, dcl_kind, ctor_dtor_or_conv_p) ...@@ -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 /* This is either a parameter-declaration-clause, or a
parenthesized declarator. When we know we are parsing 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 if FIRST is true. For instance, `(int)' is a
parameter-declaration-clause, with an omitted parameter-declaration-clause, with an omitted
direct-abstract-declarator. But `((*))', is a direct-abstract-declarator. But `((*))', is a
...@@ -11851,7 +11864,7 @@ cp_parser_class_head (parser, ...@@ -11851,7 +11864,7 @@ cp_parser_class_head (parser,
Handle this gracefully by accepting the extra qualifier, and then Handle this gracefully by accepting the extra qualifier, and then
issuing an error about it later if this really is a 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. */ specifier, remain silent. */
if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)) if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false))
qualified_p = true; qualified_p = true;
...@@ -11920,7 +11933,8 @@ cp_parser_class_head (parser, ...@@ -11920,7 +11933,8 @@ cp_parser_class_head (parser,
if (TYPE_P (scope) if (TYPE_P (scope)
&& CLASS_TYPE_P (scope) && CLASS_TYPE_P (scope)
&& CLASSTYPE_TEMPLATE_INFO (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; ++num_templates;
} }
} }
...@@ -13983,6 +13997,16 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) ...@@ -13983,6 +13997,16 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
bool constructor_p; bool constructor_p;
tree type_decl = NULL_TREE; tree type_decl = NULL_TREE;
bool nested_name_p; 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 /* Parse tentatively; we are going to roll back all of the tokens
consumed here. */ consumed here. */
...@@ -14830,6 +14854,28 @@ cp_parser_optional_template_keyword (cp_parser *parser) ...@@ -14830,6 +14854,28 @@ cp_parser_optional_template_keyword (cp_parser *parser)
return false; 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. */ /* Add tokens to CACHE until an non-nested END token appears. */
static void static void
......
...@@ -174,6 +174,9 @@ throw_bad_cast (void) ...@@ -174,6 +174,9 @@ throw_bad_cast (void)
return build_call (fn, NULL_TREE); 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 static tree
throw_bad_typeid (void) throw_bad_typeid (void)
{ {
...@@ -187,17 +190,19 @@ throw_bad_typeid (void) ...@@ -187,17 +190,19 @@ throw_bad_typeid (void)
fn = push_throw_library_fn (fn, t); 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. /* Return an lvalue expression whose type is "const std::type_info"
If EXP is a reference to a polymorphic class, return the dynamic type; 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. */ otherwise return the static type of the expression. */
static tree static tree
get_tinfo_decl_dynamic (tree exp) get_tinfo_decl_dynamic (tree exp)
{ {
tree type; tree type;
tree t;
if (exp == error_mark_node) if (exp == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -221,18 +226,18 @@ get_tinfo_decl_dynamic (tree exp) ...@@ -221,18 +226,18 @@ get_tinfo_decl_dynamic (tree exp)
if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0)) if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
{ {
/* build reference to type_info from vtable. */ /* build reference to type_info from vtable. */
tree t;
tree index; tree index;
/* The RTTI information is at index -1. */ /* The RTTI information is at index -1. */
index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1); index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1);
t = build_vtbl_ref (exp, index); t = build_vtbl_ref (exp, index);
TREE_TYPE (t) = type_info_ptr_type; TREE_TYPE (t) = type_info_ptr_type;
return t;
} }
else
/* Otherwise return the type_info for the static type of the expr. */ /* Otherwise return the type_info for the static type of the expr. */
return get_tinfo_ptr (TYPE_MAIN_VARIANT (type)); t = get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
return build_indirect_ref (t, NULL);
} }
static bool static bool
...@@ -253,6 +258,9 @@ typeid_ok_p (void) ...@@ -253,6 +258,9 @@ typeid_ok_p (void)
return true; return true;
} }
/* Return an expression for "typeid(EXP)". The expression returned is
an lvalue of type "const std::type_info". */
tree tree
build_typeid (tree exp) build_typeid (tree exp)
{ {
...@@ -280,8 +288,6 @@ build_typeid (tree exp) ...@@ -280,8 +288,6 @@ build_typeid (tree exp)
if (exp == error_mark_node) if (exp == error_mark_node)
return error_mark_node; return error_mark_node;
exp = build_indirect_ref (exp, NULL);
if (cond) if (cond)
{ {
tree bad = throw_bad_typeid (); tree bad = throw_bad_typeid ();
...@@ -289,7 +295,7 @@ build_typeid (tree exp) ...@@ -289,7 +295,7 @@ build_typeid (tree exp)
exp = build (COND_EXPR, TREE_TYPE (exp), cond, exp, bad); exp = build (COND_EXPR, TREE_TYPE (exp), cond, exp, bad);
} }
return convert_from_reference (exp); return exp;
} }
/* Generate the NTBS name of a type. */ /* Generate the NTBS name of a type. */
......
...@@ -1865,27 +1865,6 @@ build_class_member_access_expr (tree object, tree member, ...@@ -1865,27 +1865,6 @@ build_class_member_access_expr (tree object, tree member,
my_friendly_assert (DECL_P (member) || BASELINK_P (member), my_friendly_assert (DECL_P (member) || BASELINK_P (member),
20020801); 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] /* [expr.ref]
The type of the first expression shall be "class object" (of a 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, ...@@ -1925,6 +1904,34 @@ build_class_member_access_expr (tree object, tree member,
return error_mark_node; 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 /* In [expr.ref], there is an explicit list of the valid choices for
MEMBER. We check for each of those cases here. */ MEMBER. We check for each of those cases here. */
if (TREE_CODE (member) == VAR_DECL) if (TREE_CODE (member) == VAR_DECL)
......
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> 2003-01-10 Josef Zlomek <zlomekj@suse.cz>
* gcc.c-torture/compile/20030110-1.c: New test. * gcc.c-torture/compile/20030110-1.c: New test.
......
#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;
};
#include <typeinfo>
struct A {
virtual ~A() {}
};
int main() {
A* a = new A;
typeid(*a).name();
}
template <int i> struct A;
template <> struct A<0> { struct B; };
struct A<0>::B {};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment