After . or ->, when we see a name followed by < we look for a template
name, first in the scope of the object expression and then in the
enclosing scope. DR 141 clarified that when we look in the enclosing
scope, we only consider class templates, since there's no way a
non-member function template could be correct in that situation.
When I fixed that, I found that we were failing to do the lookup in the
object scope in the case where that scope is the current instantiation,
so I needed to fix that as well.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit b3a4e73d776023398007c3d41bf957cee1792683
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Feb 8 23:46:24 2016 -0500
PR c++/10200
* parser.c (cp_parser_lookup_name): When looking for a template
after . or ->, only consider class templates.
(cp_parser_postfix_dot_deref_expression): Handle the current
instantiation. Remember a dependent object expression.
* typeck2.c (build_x_arrow): Handle the current instantiation.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6f47edf..07d1821 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7184,8 +7184,16 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
if (token_type == CPP_DEREF)
postfix_expression = build_x_arrow (location, postfix_expression,
tf_warning_or_error);
- /* Check to see whether or not the expression is type-dependent. */
- dependent_p = type_dependent_expression_p (postfix_expression);
+ /* According to the standard, no expression should ever have
+ reference type. Unfortunately, we do not currently match
+ the standard in this respect in that our internal representation
+ of an expression may have reference type even when the standard
+ says it does not. Therefore, we have to manually obtain the
+ underlying type here. */
+ scope = non_reference (TREE_TYPE (postfix_expression));
+ /* Check to see whether or not the expression is type-dependent and
+ not the current instantiation. */
+ dependent_p = !scope || dependent_scope_p (scope);
/* The identifier following the `->' or `.' is not qualified. */
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
@@ -7194,16 +7202,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
/* Enter the scope corresponding to the type of the object
given by the POSTFIX_EXPRESSION. */
- if (!dependent_p && TREE_TYPE (postfix_expression) != NULL_TREE)
+ if (!dependent_p)
{
- scope = TREE_TYPE (postfix_expression);
- /* According to the standard, no expression should ever have
- reference type. Unfortunately, we do not currently match
- the standard in this respect in that our internal representation
- of an expression may have reference type even when the standard
- says it does not. Therefore, we have to manually obtain the
- underlying type here. */
- scope = non_reference (scope);
/* The type of the POSTFIX_EXPRESSION must be complete. */
if (scope == unknown_type_node)
{
@@ -7215,7 +7215,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
required to be of complete type for purposes of class member
access (5.2.5) outside the member function body. */
else if (postfix_expression != current_class_ref
- && !(processing_template_decl && scope == current_class_type))
+ && !(processing_template_decl
+ && current_class_type
+ && (same_type_ignoring_top_level_qualifiers_p
+ (scope, current_class_type))))
scope = complete_type_or_else (scope, NULL_TREE);
/* Let the name lookup machinery know that we are processing a
class member access expression. */
@@ -7231,6 +7234,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
if (scope == error_mark_node)
postfix_expression = error_mark_node;
}
+ else
+ /* Tell cp_parser_lookup_name that there was an object, even though it's
+ type-dependent. */
+ parser->context->object_type = unknown_type_node;
/* Assume this expression is not a pseudo-destructor access. */
pseudo_destructor_p = false;
@@ -24720,10 +24727,15 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
decl = NULL_TREE;
if (!decl)
- /* Look it up in the enclosing context. */
- decl = lookup_name_real (name, tag_type != none_type,
+ /* Look it up in the enclosing context. DR 141: When looking for a
+ template-name after -> or ., only consider class templates. */
+ decl = lookup_name_real (name, tag_type != none_type || is_template,
/*nonclass=*/0,
/*block_p=*/true, is_namespace, 0);
+ if (object_type == unknown_type_node)
+ /* The object is type-dependent, so we can't look anything up; we used
+ this to get the DR 141 behavior. */
+ object_type = NULL_TREE;
parser->object_scope = object_type;
parser->qualifying_scope = NULL_TREE;
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 2a76c96..54a432f 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1694,7 +1694,10 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
if (processing_template_decl)
{
- if (type_dependent_expression_p (expr))
+ if (type && TREE_CODE (type) == POINTER_TYPE
+ && !dependent_scope_p (TREE_TYPE (type)))
+ /* Pointer to current instantiation, don't treat as dependent. */;
+ else if (type_dependent_expression_p (expr))
return build_min_nt_loc (loc, ARROW_EXPR, expr);
expr = build_non_dependent_expr (expr);
}
diff --git a/gcc/testsuite/g++.dg/lookup/member2.C b/gcc/testsuite/g++.dg/lookup/member2.C
new file mode 100644
index 0000000..5478448
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/member2.C
@@ -0,0 +1,5 @@
+// PR c++/10200
+
+template<class Tp> inline void end(Tp) { }
+
+template <typename T> bool tnegative(const T& t) { return t.end < 0; }