summaryrefslogtreecommitdiffstats
path: root/gcc/cp
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2005-10-16 19:38:57 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2005-10-16 19:38:57 +0000
commitfbb01da7f6e67f35be3c62f1c118d9595952d1f6 (patch)
tree76f4797c33c693120da1fa591e01740f0bef605d /gcc/cp
parentec7d1569362ff61904f7d618062fd00b89fc63f4 (diff)
downloadppe42-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/ChangeLog45
-rw-r--r--gcc/cp/cp-tree.h16
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/mangle.c9
-rw-r--r--gcc/cp/parser.c192
-rw-r--r--gcc/cp/pt.c34
-rw-r--r--gcc/cp/semantics.c91
-rw-r--r--gcc/cp/tree.c17
-rw-r--r--gcc/cp/typeck.c60
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)
OpenPOWER on IntegriCloud