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:
parent
0cdca92b46
commit
2050a1bbac
10 changed files with 208 additions and 212 deletions
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
129
gcc/cp/decl2.c
129
gcc/cp/decl2.c
|
@ -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
|
||||
|
|
142
gcc/cp/parser.c
142
gcc/cp/parser.c
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
9
gcc/testsuite/g++.dg/parse/lookup1.C
Normal file
9
gcc/testsuite/g++.dg/parse/lookup1.C
Normal 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;
|
||||
};
|
11
gcc/testsuite/g++.dg/rtti/typeid1.C
Normal file
11
gcc/testsuite/g++.dg/rtti/typeid1.C
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <typeinfo>
|
||||
|
||||
struct A {
|
||||
virtual ~A() {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
A* a = new A;
|
||||
typeid(*a).name();
|
||||
}
|
||||
|
3
gcc/testsuite/g++.dg/template/spec5.C
Normal file
3
gcc/testsuite/g++.dg/template/spec5.C
Normal file
|
@ -0,0 +1,3 @@
|
|||
template <int i> struct A;
|
||||
template <> struct A<0> { struct B; };
|
||||
struct A<0>::B {};
|
Loading…
Add table
Reference in a new issue