diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-16 19:38:57 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-16 19:38:57 +0000 |
commit | fbb01da7f6e67f35be3c62f1c118d9595952d1f6 (patch) | |
tree | 76f4797c33c693120da1fa591e01740f0bef605d /gcc/cp | |
parent | ec7d1569362ff61904f7d618062fd00b89fc63f4 (diff) | |
download | ppe42-gcc-fbb01da7f6e67f35be3c62f1c118d9595952d1f6.tar.gz ppe42-gcc-fbb01da7f6e67f35be3c62f1c118d9595952d1f6.zip |
PR c++/22137
* cp-tree.h (QUALIFIED_NAME_IS_TEMPLATE): New macro.
(check_template_keyword): New function.
(finish_id_expression): Change prototoype.
(finish_qualified_id_expr): Change prototype.
(build_qualified_name): New function.
(finish_class_member_access_expr): Change prototype.
* init.c (build_offset_ref): Use build_qualified_name.
* mangle.c (write_expression): Likewise.
* parser.c (cp_parser_primary_expression): Remove qualifying_class
parameter. Add address_p and template_arg_p. Use
build_qualified_name.
(cp_parser_id_expression): Default *template_p to
template_keyword_p. Check for invalid uses of the template
keyword.
(cp_parser_postfix_expression): Eliminate special handling for
qualified names. Adjust call to cp_parser_primary_expression.
(cp_parser_postfix_dot_deref_expression): Adjust call to
cp_parser_id_expression and finish_class_member_access_expr.
(cp_parser_template_argument_list): Add comment.
(cp_parser_template_argument): Adjust use of
cp_parser_primary_expression. Remove call to
finish_qualified_id_expr.
(cp_parser_lookup_name): Use build_qualified_name.
* pt.c (tsubst): Use build_qualified_name.
(tsubst_qualified_id): Likewise. Adjust call to
finish_qualified_id_expr.
(tsubst_copy): Use build_qualified_name.
(tsubst_copy_and_build): Adjusts call to finish_id_expression and
finish_class_member_access_expr.
* semantics.c (finish_non_static_data_member): Use
build_qualified_name.
(finish_qualified_id_expr): Add template_p and template_arg_p
parameters.
(finish_id_expression): Remove qualifiying_class parameter. Add
template_p, done, address_p, and template_arg_p. Use
build_qualified_name. Adjust calls to
finish_class_member_acess_expr.
* tree.c (build_qualified_name): New function.
* typeck.c (check_template_keyword): New function.
(finish_class_member_access_expr): Add template_p argument. Check
for invalid uses of the template keyword.
PR c++/22137
* g++.dg/parse/template18.C: New test.
* g++.dg/template/nontype15.C: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@105463 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 45 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 16 | ||||
-rw-r--r-- | gcc/cp/init.c | 3 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 9 | ||||
-rw-r--r-- | gcc/cp/parser.c | 192 | ||||
-rw-r--r-- | gcc/cp/pt.c | 34 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 91 | ||||
-rw-r--r-- | gcc/cp/tree.c | 17 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 60 |
9 files changed, 327 insertions, 140 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 51089eb9f90..9d3930fe23e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,48 @@ +2005-10-16 Mark Mitchell <mark@codesourcery.com> + + PR c++/22137 + * cp-tree.h (QUALIFIED_NAME_IS_TEMPLATE): New macro. + (check_template_keyword): New function. + (finish_id_expression): Change prototoype. + (finish_qualified_id_expr): Change prototype. + (build_qualified_name): New function. + (finish_class_member_access_expr): Change prototype. + * init.c (build_offset_ref): Use build_qualified_name. + * mangle.c (write_expression): Likewise. + * parser.c (cp_parser_primary_expression): Remove qualifying_class + parameter. Add address_p and template_arg_p. Use + build_qualified_name. + (cp_parser_id_expression): Default *template_p to + template_keyword_p. Check for invalid uses of the template + keyword. + (cp_parser_postfix_expression): Eliminate special handling for + qualified names. Adjust call to cp_parser_primary_expression. + (cp_parser_postfix_dot_deref_expression): Adjust call to + cp_parser_id_expression and finish_class_member_access_expr. + (cp_parser_template_argument_list): Add comment. + (cp_parser_template_argument): Adjust use of + cp_parser_primary_expression. Remove call to + finish_qualified_id_expr. + (cp_parser_lookup_name): Use build_qualified_name. + * pt.c (tsubst): Use build_qualified_name. + (tsubst_qualified_id): Likewise. Adjust call to + finish_qualified_id_expr. + (tsubst_copy): Use build_qualified_name. + (tsubst_copy_and_build): Adjusts call to finish_id_expression and + finish_class_member_access_expr. + * semantics.c (finish_non_static_data_member): Use + build_qualified_name. + (finish_qualified_id_expr): Add template_p and template_arg_p + parameters. + (finish_id_expression): Remove qualifiying_class parameter. Add + template_p, done, address_p, and template_arg_p. Use + build_qualified_name. Adjust calls to + finish_class_member_acess_expr. + * tree.c (build_qualified_name): New function. + * typeck.c (check_template_keyword): New function. + (finish_class_member_access_expr): Add template_p argument. Check + for invalid uses of the template keyword. + 2005-10-15 Mark Mitchell <mark@codesourcery.com> PR c++/21347 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 42eed5f6fd4..9a2becc3c94 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -51,6 +51,7 @@ struct diagnostic_context; BIND_EXPR_TRY_BLOCK (in BIND_EXPR) TYPENAME_IS_ENUM_P (in TYPENAME_TYPE) REFERENCE_REF_P (in INDIRECT_EXPR) + QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -2933,6 +2934,11 @@ extern void decl_shadowed_for_var_insert (tree, tree); #define THUNK_TARGET(NODE) \ (DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes) +/* True for a SCOPE_REF iff the "template" keyword was used to + indicate that the qualified name denotes a template. */ +#define QUALIFIED_NAME_IS_TEMPLATE(NODE) \ + (TREE_LANG_FLAG_0 (SCOPE_REF_CHECK (NODE))) + /* These macros provide convenient access to the various _STMT nodes created when parsing template declarations. */ #define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0) @@ -4200,9 +4206,11 @@ extern tree finish_template_type (tree, tree, int); extern tree finish_base_specifier (tree, tree, bool); extern void finish_member_declaration (tree); extern void qualified_name_lookup_error (tree, tree, tree); +extern void check_template_keyword (tree); extern tree finish_id_expression (tree, tree, tree, - cp_id_kind *, tree *, + cp_id_kind *, bool, bool, bool *, + bool, bool, bool, bool, const char **); extern tree finish_typeof (tree); extern void finish_decl_cleanup (tree, tree); @@ -4212,7 +4220,8 @@ extern void finish_mem_initializers (tree); extern tree check_template_template_default_arg (tree); extern void expand_or_defer_fn (tree); extern void check_accessibility_of_qualified_id (tree, tree, tree); -extern tree finish_qualified_id_expr (tree, tree, bool, bool); +extern tree finish_qualified_id_expr (tree, tree, bool, bool, + bool, bool); extern void simplify_aggr_init_expr (tree *); extern void finalize_nrv (tree *, tree, tree); extern void note_decl_for_pch (tree); @@ -4242,6 +4251,7 @@ extern tree get_target_expr (tree); extern tree build_cplus_array_type (tree, tree); extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); +extern tree build_qualified_name (tree, tree, tree, bool); extern int is_overloaded_fn (tree); extern tree get_first_fn (tree); extern tree ovl_cons (tree, tree); @@ -4305,7 +4315,7 @@ extern tree inline_conversion (tree); extern tree decay_conversion (tree); extern tree default_conversion (tree); extern tree build_class_member_access_expr (tree, tree, tree, bool); -extern tree finish_class_member_access_expr (tree, tree); +extern tree finish_class_member_access_expr (tree, tree, bool); extern tree build_x_indirect_ref (tree, const char *); extern tree build_indirect_ref (tree, const char *); extern tree build_array_ref (tree, tree); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 20c3b356352..809b74fa98a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1344,7 +1344,8 @@ build_offset_ref (tree type, tree name, bool address_p) return name; if (dependent_type_p (type) || type_dependent_expression_p (name)) - return build_min_nt (SCOPE_REF, type, name); + return build_qualified_name (NULL_TREE, type, name, + /*template_p=*/false); if (TREE_CODE (name) == TEMPLATE_ID_EXPR) { diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 9dca2a56c55..b07012252bb 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2008,9 +2008,10 @@ write_expression (tree expr) if (code == PTRMEM_CST) { expr = build_nt (ADDR_EXPR, - build_nt (SCOPE_REF, - PTRMEM_CST_CLASS (expr), - PTRMEM_CST_MEMBER (expr))); + build_qualified_name (/*type=*/NULL_TREE, + PTRMEM_CST_CLASS (expr), + PTRMEM_CST_MEMBER (expr), + /*template_p=*/false)); code = TREE_CODE (expr); } @@ -2186,7 +2187,7 @@ write_expression (tree expr) for (i = 0; i < TREE_CODE_LENGTH (code); ++i) { tree operand = TREE_OPERAND (expr, i); - /* As a GNU expression, the middle operand of a + /* As a GNU extension, the middle operand of a conditional may be omitted. Since expression manglings are supposed to represent the input token stream, there's no good way to mangle such an diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 469cc73699f..7f279437196 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1381,7 +1381,7 @@ static bool cp_parser_translation_unit /* Expressions [gram.expr] */ static tree cp_parser_primary_expression - (cp_parser *, bool, cp_id_kind *, tree *); + (cp_parser *, bool, bool, bool, cp_id_kind *); static tree cp_parser_id_expression (cp_parser *, bool, bool, bool *, bool); static tree cp_parser_unqualified_id @@ -2716,29 +2716,25 @@ cp_parser_translation_unit (cp_parser* parser) literal: __null - CAST_P is true if this primary expression is the target of a cast. + ADDRESS_P is true iff this expression was immediately preceded by + "&" and therefore might denote a pointer-to-member. CAST_P is true + iff this expression is the target of a cast. TEMPLATE_ARG_P is + true iff this expression is a tempalte argument. - Returns a representation of the expression. - - *IDK indicates what kind of id-expression (if any) was present. - - *QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be - used as the operand of a pointer-to-member. In that case, - *QUALIFYING_CLASS gives the class that is used as the qualifying - class in the pointer-to-member. */ + Returns a representation of the expression. Upon return, *IDK + indicates what kind of id-expression (if any) was present. */ static tree cp_parser_primary_expression (cp_parser *parser, + bool address_p, bool cast_p, - cp_id_kind *idk, - tree *qualifying_class) + bool template_arg_p, + cp_id_kind *idk) { cp_token *token; /* Assume the primary expression is not an id-expression. */ *idk = CP_ID_KIND_NONE; - /* And that it cannot be used as pointer-to-member. */ - *qualifying_class = NULL_TREE; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -2964,6 +2960,8 @@ cp_parser_primary_expression (cp_parser *parser, tree id_expression; tree decl; const char *error_msg; + bool template_p; + bool done; id_expression: /* Parse the id-expression. */ @@ -2971,15 +2969,22 @@ cp_parser_primary_expression (cp_parser *parser, = cp_parser_id_expression (parser, /*template_keyword_p=*/false, /*check_dependency_p=*/true, - /*template_p=*/NULL, + &template_p, /*declarator_p=*/false); if (id_expression == error_mark_node) return error_mark_node; + token = cp_lexer_peek_token (parser->lexer); + done = (token->type != CPP_OPEN_SQUARE + && token->type != CPP_OPEN_PAREN + && token->type != CPP_DOT + && token->type != CPP_DEREF + && token->type != CPP_PLUS_PLUS + && token->type != CPP_MINUS_MINUS); /* If we have a template-id, then no further lookup is required. If the template-id was for a template-class, we will sometimes have a TYPE_DECL at this point. */ - else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR - || TREE_CODE (id_expression) == TYPE_DECL) + if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR + || TREE_CODE (id_expression) == TYPE_DECL) decl = id_expression; /* Look up the name. */ else @@ -2988,7 +2993,7 @@ cp_parser_primary_expression (cp_parser *parser, decl = cp_parser_lookup_name (parser, id_expression, none_type, - /*is_template=*/false, + template_p, /*is_namespace=*/false, /*check_dependency=*/true, &ambiguous_p); @@ -3002,14 +3007,9 @@ cp_parser_primary_expression (cp_parser *parser, decl = objc_lookup_ivar (decl, id_expression); /* If name lookup gives us a SCOPE_REF, then the - qualifying scope was dependent. Just propagate the - name. */ + qualifying scope was dependent. */ if (TREE_CODE (decl) == SCOPE_REF) - { - if (TYPE_P (TREE_OPERAND (decl, 0))) - *qualifying_class = TREE_OPERAND (decl, 0); - return decl; - } + return decl; /* Check to see if DECL is a local variable in a context where that is forbidden. */ if (parser->local_variables_forbidden_p @@ -3038,12 +3038,15 @@ cp_parser_primary_expression (cp_parser *parser, } } - decl = finish_id_expression (id_expression, decl, parser->scope, - idk, qualifying_class, - parser->integral_constant_expression_p, - parser->allow_non_integral_constant_expression_p, - &parser->non_integral_constant_expression_p, - &error_msg); + decl = (finish_id_expression + (id_expression, decl, parser->scope, + idk, + parser->integral_constant_expression_p, + parser->allow_non_integral_constant_expression_p, + &parser->non_integral_constant_expression_p, + template_p, done, address_p, + template_arg_p, + &error_msg)); if (error_msg) cp_parser_error (parser, error_msg); return decl; @@ -3107,7 +3110,7 @@ cp_parser_id_expression (cp_parser *parser, /* Assume the `template' keyword was not used. */ if (template_p) - *template_p = false; + *template_p = template_keyword_p; /* Look for the optional `::' operator. */ global_scope_p @@ -3627,23 +3630,36 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, } break; } - /* We've found one valid nested-name-specifier. */ success = true; - /* Make sure we look in the right scope the next time through - the loop. */ - parser->scope = (TREE_CODE (new_scope) == TYPE_DECL - ? TREE_TYPE (new_scope) - : new_scope); + /* Name lookup always gives us a DECL. */ + if (TREE_CODE (new_scope) == TYPE_DECL) + new_scope = TREE_TYPE (new_scope); + /* Uses of "template" must be followed by actual templates. */ + if (template_keyword_p + && !(CLASS_TYPE_P (new_scope) + && ((CLASSTYPE_USE_TEMPLATE (new_scope) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (new_scope))) + || CLASSTYPE_IS_TEMPLATE (new_scope))) + && !(TREE_CODE (new_scope) == TYPENAME_TYPE + && (TREE_CODE (TYPENAME_TYPE_FULLNAME (new_scope)) + == TEMPLATE_ID_EXPR))) + pedwarn (TYPE_P (new_scope) + ? "%qT is not a template" + : "%qD is not a template", + new_scope); /* If it is a class scope, try to complete it; we are about to be looking up names inside the class. */ - if (TYPE_P (parser->scope) + if (TYPE_P (new_scope) /* Since checking types for dependency can be expensive, avoid doing it if the type is already complete. */ - && !COMPLETE_TYPE_P (parser->scope) + && !COMPLETE_TYPE_P (new_scope) /* Do not try to complete dependent types. */ - && !dependent_type_p (parser->scope)) - complete_type (parser->scope); + && !dependent_type_p (new_scope)) + new_scope = complete_type (new_scope); + /* Make sure we look in the right scope the next time through + the loop. */ + parser->scope = new_scope; } /* Retrieve any deferred checks. Do not pop this access checks yet @@ -3818,10 +3834,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) enum rid keyword; cp_id_kind idk = CP_ID_KIND_NONE; tree postfix_expression = NULL_TREE; - /* Non-NULL only if the current postfix-expression can be used to - form a pointer-to-member. In that case, QUALIFYING_CLASS is the - class used to qualify the member. */ - tree qualifying_class = NULL_TREE; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -4073,38 +4085,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p) } /* It must be a primary-expression. */ - postfix_expression = cp_parser_primary_expression (parser, - cast_p, - &idk, - &qualifying_class); + postfix_expression + = cp_parser_primary_expression (parser, address_p, cast_p, + /*template_arg_p=*/false, + &idk); } break; } - /* If we were avoiding committing to the processing of a - qualified-id until we knew whether or not we had a - pointer-to-member, we now know. */ - if (qualifying_class) - { - bool done; - - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); - done = (token->type != CPP_OPEN_SQUARE - && token->type != CPP_OPEN_PAREN - && token->type != CPP_DOT - && token->type != CPP_DEREF - && token->type != CPP_PLUS_PLUS - && token->type != CPP_MINUS_MINUS); - - postfix_expression = finish_qualified_id_expr (qualifying_class, - postfix_expression, - done, - address_p); - if (done) - return postfix_expression; - } - /* Keep looping until the postfix-expression is complete. */ while (true) { @@ -4392,7 +4380,6 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, { tree name; bool dependent_p; - bool template_p; bool pseudo_destructor_p; tree scope = NULL_TREE; @@ -4463,12 +4450,14 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, /* If the SCOPE is not a scalar type, we are looking at an ordinary class member access expression, rather than a pseudo-destructor-name. */ - template_p = cp_parser_optional_template_keyword (parser); + bool template_p; /* Parse the id-expression. */ - name = cp_parser_id_expression (parser, template_p, - /*check_dependency_p=*/true, - /*template_p=*/NULL, - /*declarator_p=*/false); + name = (cp_parser_id_expression + (parser, + cp_parser_optional_template_keyword (parser), + /*check_dependency_p=*/true, + &template_p, + /*declarator_p=*/false)); /* In general, build a SCOPE_REF if the member name is qualified. However, if the name was not dependent and has already been resolved; there is no need to build the SCOPE_REF. For example; @@ -4495,7 +4484,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, { if (name != error_mark_node && !BASELINK_P (name) && parser->scope) { - name = build_nt (SCOPE_REF, parser->scope, name); + name = build_qualified_name (/*type=*/NULL_TREE, + parser->scope, + name, + template_p); parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; @@ -4504,7 +4496,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, adjust_result_of_qualified_name_lookup (name, BINFO_TYPE (BASELINK_BINFO (name)), scope); postfix_expression - = finish_class_member_access_expr (postfix_expression, name); + = finish_class_member_access_expr (postfix_expression, name, + template_p); } } @@ -8917,6 +8910,7 @@ cp_parser_template_argument_list (cp_parser* parser) parser->integral_constant_expression_p = false; saved_non_ice_p = parser->non_integral_constant_expression_p; parser->non_integral_constant_expression_p = false; + /* Parse the arguments. */ do { tree argument; @@ -8981,7 +8975,6 @@ cp_parser_template_argument (cp_parser* parser) bool maybe_type_id = false; cp_token *token; cp_id_kind idk; - tree qualifying_class; /* There's really no way to know what we're looking at, so we just try each alternative in order. @@ -9073,9 +9066,10 @@ cp_parser_template_argument (cp_parser* parser) { cp_parser_parse_tentatively (parser); argument = cp_parser_primary_expression (parser, + /*adress_p=*/false, /*cast_p=*/false, - &idk, - &qualifying_class); + /*template_arg_p=*/true, + &idk); if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX || !cp_parser_next_token_ends_template_argument_p (parser)) cp_parser_simulate_error (parser); @@ -9098,9 +9092,10 @@ cp_parser_template_argument (cp_parser* parser) { cp_parser_parse_tentatively (parser); argument = cp_parser_primary_expression (parser, + address_p, /*cast_p=*/false, - &idk, - &qualifying_class); + /*template_arg_p=*/true, + &idk); if (cp_parser_error_occurred (parser) || !cp_parser_next_token_ends_template_argument_p (parser)) cp_parser_abort_tentative_parse (parser); @@ -9112,16 +9107,7 @@ cp_parser_template_argument (cp_parser* parser) argument = TREE_OPERAND (argument, 0); } - /* If ADDRESS_P, then we use finish_qualified_id_expr so - that we get a pointer-to-member, if appropriate. - However, if ADDRESS_P is false, we don't want to turn - "T::f" into "(*this).T::f". */ - if (qualifying_class && address_p) - argument = finish_qualified_id_expr (qualifying_class, - argument, - /*done=*/true, - /*address_p=*/true); - else if (TREE_CODE (argument) == BASELINK) + if (TREE_CODE (argument) == BASELINK) /* We don't need the information about what class was used to name the overloaded functions. */ argument = BASELINK_FUNCTIONS (argument); @@ -14480,7 +14466,8 @@ cp_parser_label_declaration (cp_parser* parser) static tree cp_parser_lookup_name (cp_parser *parser, tree name, enum tag_types tag_type, - bool is_template, bool is_namespace, + bool is_template, + bool is_namespace, bool check_dependency, bool *ambiguous_p) { @@ -14575,12 +14562,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name, /*complain=*/1); decl = TYPE_NAME (type); } - else if (is_template) + else if (is_template + && (cp_parser_next_token_ends_template_argument_p (parser) + || cp_lexer_next_token_is (parser->lexer, + CPP_CLOSE_PAREN))) decl = make_unbound_class_template (parser->scope, name, NULL_TREE, /*complain=*/1); else - decl = build_nt (SCOPE_REF, parser->scope, name); + decl = build_qualified_name (/*type=*/NULL_TREE, + parser->scope, name, + is_template); } else { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4d93724927a..1ef5669a82d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7544,7 +7544,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (e1 == error_mark_node || e2 == error_mark_node) return error_mark_node; - return build_nt (TREE_CODE (t), e1, e2); + return build_qualified_name (/*type=*/NULL_TREE, + e1, e2, QUALIFIED_NAME_IS_TEMPLATE (t)); } case TYPEOF_TYPE: @@ -7675,7 +7676,9 @@ tsubst_qualified_id (tree qualified_id, tree args, expr = name; if (dependent_type_p (scope)) - return build_nt (SCOPE_REF, scope, expr); + return build_qualified_name (/*type=*/NULL_TREE, + scope, expr, + QUALIFIED_NAME_IS_TEMPLATE (qualified_id)); if (!BASELINK_P (name) && !DECL_P (expr)) { @@ -7725,7 +7728,10 @@ tsubst_qualified_id (tree qualified_id, tree args, { expr = (adjust_result_of_qualified_name_lookup (expr, scope, current_class_type)); - expr = finish_qualified_id_expr (scope, expr, done, address_p); + expr = (finish_qualified_id_expr + (scope, expr, done, address_p, + QUALIFIED_NAME_IS_TEMPLATE (qualified_id), + /*template_arg_p=*/false)); } if (TREE_CODE (expr) != SCOPE_REF) @@ -7912,7 +7918,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) name = tsubst_copy (TREE_OPERAND (name, 0), args, complain, in_decl); name = build1 (BIT_NOT_EXPR, NULL_TREE, name); - name = build_nt (SCOPE_REF, base, name); + name = build_qualified_name (/*type=*/NULL_TREE, + base, name, + /*template_p=*/false); } else if (TREE_CODE (name) == BASELINK) name = tsubst_baselink (name, @@ -7954,7 +7962,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case LT_EXPR: case GT_EXPR: case COMPOUND_EXPR: - case SCOPE_REF: case DOTSTAR_EXPR: case MEMBER_REF: case PREDECREMENT_EXPR: @@ -7965,6 +7972,14 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) (code, tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl), tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl)); + case SCOPE_REF: + return build_qualified_name (/*type=*/NULL_TREE, + tsubst_copy (TREE_OPERAND (t, 0), + args, complain, in_decl), + tsubst_copy (TREE_OPERAND (t, 1), + args, complain, in_decl), + QUALIFIED_NAME_IS_TEMPLATE (t)); + case ARRAY_REF: return build_nt (ARRAY_REF, @@ -8438,7 +8453,6 @@ tsubst_copy_and_build (tree t, { tree decl; cp_id_kind idk; - tree qualifying_class; bool non_integral_constant_expression_p; const char *error_msg; @@ -8458,10 +8472,13 @@ tsubst_copy_and_build (tree t, decl = finish_id_expression (t, decl, NULL_TREE, &idk, - &qualifying_class, /*integral_constant_expression_p=*/false, /*allow_non_integral_constant_expression_p=*/false, &non_integral_constant_expression_p, + /*template_p=*/false, + /*done=*/true, + /*address_p=*/false, + /*template_arg_p=*/false, &error_msg); if (error_msg) error (error_msg); @@ -8872,7 +8889,8 @@ tsubst_copy_and_build (tree t, else if (TREE_CODE (member) == FIELD_DECL) return finish_non_static_data_member (member, object, NULL_TREE); - return finish_class_member_access_expr (object, member); + return finish_class_member_access_expr (object, member, + /*template_p=*/false); } case THROW_EXPR: diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d870fda6ba2..5ccc7c75709 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1407,8 +1407,10 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF for now. */ if (processing_template_decl) - return build_min (SCOPE_REF, TREE_TYPE (decl), - qualifying_scope, DECL_NAME (decl)); + return build_qualified_name (TREE_TYPE (decl), + qualifying_scope, + DECL_NAME (decl), + /*template_p=*/false); perform_or_defer_access_check (TYPE_BINFO (access_type), decl); @@ -1494,15 +1496,24 @@ check_accessibility_of_qualified_id (tree decl, class named to the left of the "::" operator. DONE is true if this expression is a complete postfix-expression; it is false if this expression is followed by '->', '[', '(', etc. ADDRESS_P is true - iff this expression is the operand of '&'. */ + iff this expression is the operand of '&'. TEMPLATE_P is true iff + the qualified-id was of the form "A::template B". TEMPLATE_ARG_P + is true iff this qualified name appears as a template argument. */ tree -finish_qualified_id_expr (tree qualifying_class, tree expr, bool done, - bool address_p) +finish_qualified_id_expr (tree qualifying_class, + tree expr, + bool done, + bool address_p, + bool template_p, + bool template_arg_p) { if (error_operand_p (expr)) return error_mark_node; + if (template_p) + check_template_keyword (expr); + /* If EXPR occurs as the operand of '&', use special handling that permits a pointer-to-member. */ if (address_p && done) @@ -1514,7 +1525,13 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done, return expr; } - if (TREE_CODE (expr) == FIELD_DECL) + /* Within the scope of a class, turn references to non-static + members into expression of the form "this->...". */ + if (template_arg_p) + /* But, within a template argument, we do not want make the + transformation, as there is no "this" pointer. */ + ; + else if (TREE_CODE (expr) == FIELD_DECL) expr = finish_non_static_data_member (expr, current_class_ref, qualifying_class); else if (BASELINK_P (expr) && !processing_template_decl) @@ -2383,6 +2400,13 @@ qualified_name_lookup_error (tree scope, tree name, tree decl) constant-expression, but a non-constant expression is also permissible. + DONE is true if this expression is a complete postfix-expression; + it is false if this expression is followed by '->', '[', '(', etc. + ADDRESS_P is true iff this expression is the operand of '&'. + TEMPLATE_P is true iff the qualified-id was of the form + "A::template B". TEMPLATE_ARG_P is true iff this qualified name + appears as a template argument. + If an error occurs, and it is the kind of error that might cause the parser to abort a tentative parse, *ERROR_MSG is filled in. It is the caller's responsibility to issue the message. *ERROR_MSG @@ -2401,10 +2425,13 @@ finish_id_expression (tree id_expression, tree decl, tree scope, cp_id_kind *idk, - tree *qualifying_class, bool integral_constant_expression_p, bool allow_non_integral_constant_expression_p, bool *non_integral_constant_expression_p, + bool template_p, + bool done, + bool address_p, + bool template_arg_p, const char **error_msg) { /* Initialize the output parameters. */ @@ -2610,20 +2637,32 @@ finish_id_expression (tree id_expression, dependent. */ if (scope) { - if (TYPE_P (scope)) - *qualifying_class = scope; /* Since this name was dependent, the expression isn't constant -- yet. No error is issued because it might be constant when things are instantiated. */ if (integral_constant_expression_p) *non_integral_constant_expression_p = true; - if (TYPE_P (scope) && dependent_type_p (scope)) - return build_nt (SCOPE_REF, scope, id_expression); - else if (TYPE_P (scope) && DECL_P (decl)) - return convert_from_reference - (build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression)); - else - return convert_from_reference (decl); + if (TYPE_P (scope)) + { + if (address_p && done) + decl = finish_qualified_id_expr (scope, decl, + done, address_p, + template_p, + template_arg_p); + else if (dependent_type_p (scope)) + decl = build_qualified_name (/*type=*/NULL_TREE, + scope, + id_expression, + template_p); + else if (DECL_P (decl)) + decl = build_qualified_name (TREE_TYPE (decl), + scope, + id_expression, + template_p); + } + if (TREE_TYPE (decl)) + decl = convert_from_reference (decl); + return decl; } /* A TEMPLATE_ID already contains all the information we need. */ @@ -2703,14 +2742,20 @@ finish_id_expression (tree id_expression, mark_used (decl); if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl)) - *qualifying_class = scope; + decl = finish_qualified_id_expr (scope, + decl, + done, + address_p, + template_p, + template_arg_p); else { tree r = convert_from_reference (decl); - if (processing_template_decl - && TYPE_P (scope)) - r = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl); + if (processing_template_decl && TYPE_P (scope)) + r = build_qualified_name (TREE_TYPE (r), + scope, decl, + template_p); decl = r; } } @@ -2734,13 +2779,15 @@ finish_id_expression (tree id_expression, if (!really_overloaded_fn (decl)) mark_used (first_fn); - if (TREE_CODE (first_fn) == FUNCTION_DECL + if (!template_arg_p + && TREE_CODE (first_fn) == FUNCTION_DECL && DECL_FUNCTION_MEMBER_P (first_fn) && !shared_member_p (decl)) { /* A set of member functions. */ decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0); - return finish_class_member_access_expr (decl, id_expression); + return finish_class_member_access_expr (decl, id_expression, + /*template_p=*/false); } } else diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 954a8093a95..15ee56c7c87 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -805,6 +805,23 @@ debug_binfo (tree elem) } } +/* Build a representation for the qualified name SCOPE::NAME. TYPE is + the type of the result expression, if known, or NULL_TREE if the + resulting expression is type-dependent. If TEMPLATE_P is true, + NAME is known to be a template because the user explicitly used the + "template" keyword after the "::". + + All SCOPE_REFs should be built by use of this function. */ + +tree +build_qualified_name (tree type, tree scope, tree name, bool template_p) +{ + tree t; + t = build2 (SCOPE_REF, type, scope, name); + QUALIFIED_NAME_IS_TEMPLATE (t) = template_p; + return t; +} + int is_overloaded_fn (tree x) { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index d39b53ae967..bc34a403806 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1841,16 +1841,69 @@ lookup_destructor (tree object, tree scope, tree dtor_name) return expr; } +/* An expression of the form "A::template B" has been resolved to + DECL. Issue a diagnostic if B is not a template or template + specialization. */ + +void +check_template_keyword (tree decl) +{ + /* The standard says: + + [temp.names] + + If a name prefixed by the keyword template is not a member + template, the program is ill-formed. + + DR 228 removed the restriction that the template be a member + template. + + DR 96, if accepted would add the further restriction that explcit + template arguments must be provided if the template keyword is + used, but, as of 2005-10-16, that DR is still in "drafting". If + this DR is accepted, then the semantic checks here can be + simplified, as the entity named must in fact be a template + specialization, rather than, as at present, a set of overloaded + functions containing at least one template function. */ + if (TREE_CODE (decl) != TEMPLATE_DECL + && TREE_CODE (decl) != TEMPLATE_ID_EXPR) + { + if (!is_overloaded_fn (decl)) + pedwarn ("%qD is not a template", decl); + else + { + tree fns; + if (BASELINK_P (decl)) + fns = BASELINK_FUNCTIONS (decl); + while (fns) + { + tree fn = OVL_CURRENT (fns); + if (TREE_CODE (fn) == TEMPLATE_DECL + || TREE_CODE (fn) == TEMPLATE_ID_EXPR) + break; + if (TREE_CODE (fn) == FUNCTION_DECL + && DECL_USE_TEMPLATE (fn) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (fn))) + break; + fns = OVL_NEXT (fns); + } + if (!fns) + pedwarn ("%qD is not a template", decl); + } + } +} + /* This function is called by the parser to process a class member access expression of the form OBJECT.NAME. NAME is a node used by the parser to represent a name; it is not yet a DECL. It may, however, be a BASELINK where the BASELINK_FUNCTIONS is a TEMPLATE_ID_EXPR. Templates must be looked up by the parser, and there is no reason to do the lookup twice, so the parser keeps the - BASELINK. */ + BASELINK. TEMPLATE_P is true iff NAME was explicitly declared to + be a template via the use of the "A::template B" syntax. */ tree -finish_class_member_access_expr (tree object, tree name) +finish_class_member_access_expr (tree object, tree name, bool template_p) { tree expr; tree object_type; @@ -1995,6 +2048,9 @@ finish_class_member_access_expr (tree object, tree name) if (TREE_DEPRECATED (member)) warn_deprecated_use (member); + if (template_p) + check_template_keyword (member); + expr = build_class_member_access_expr (object, member, access_path, /*preserve_reference=*/false); if (processing_template_decl && expr != error_mark_node) |