+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.
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));
}
}
-/* 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. */
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
(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
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.
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))
- {
- 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;
+ 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))
+ {
+ cp_parser_pre_parsed_nested_name_specifier (parser);
return parser->scope;
}
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
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. */
we issue duplicate error messages. */
if (success && start >= 0)
{
- cp_token *token;
tree c;
/* Find the token that corresponds to the start of the
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;
{
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;
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:
/* 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));
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
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;
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);
{
/* 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
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;
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;
}
}
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. */
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
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)
{
fn = push_throw_library_fn (fn, t);
}
- return build_call (fn, NULL_TREE);
+ return convert_from_reference (build_call (fn, NULL_TREE));
}
\f
-/* 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;
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
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)
{
if (exp == error_mark_node)
return error_mark_node;
- exp = build_indirect_ref (exp, NULL);
-
if (cond)
{
tree bad = throw_bad_typeid ();
exp = build (COND_EXPR, TREE_TYPE (exp), cond, exp, bad);
}
- return convert_from_reference (exp);
+ return exp;
}
/* Generate the NTBS name of a type. */
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
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)
+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.
--- /dev/null
+#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;
+};
--- /dev/null
+#include <typeinfo>
+
+struct A {
+ virtual ~A() {}
+};
+
+int main() {
+ A* a = new A;
+ typeid(*a).name();
+}
+
--- /dev/null
+template <int i> struct A;
+template <> struct A<0> { struct B; };
+struct A<0>::B {};