81204 is a regression whereby previously we would accidentally get the
parsing of res.template set<I> right because when we did the lookup in
the surrounding context, we found the function template and then
ignored it.  This patch partially reverts the handling of .template to
how it was in GCC 6.

But this bug is really a special case of 54769; we should be treating
that name as dependent and not doing a lookup in the enclosing context
at all.  As I noted in discussion of 55576, we need to pass
template_keyword_p into nested_name_specifier_opt.  So this patch does
that, and also adjusts cp_parser_template_name to consider object
scope.

With that change, we see TEMPLATE_ID_EXPR in more error cases, so I
adjusted cp_parser_template_id to use the range on those expression
nodes as well as on the replacement token.

45976 and 55639 are cases where we gave unhelpful diagnostics for uses
of ::template that are pedantically ill-formed, but harmless and
accepted by other compilers.  So these patches fix G++ to accept them
with a pedwarn.

Tested x86_64-pc-linux-gnu, applying to trunk.  81204 also to 7.
commit 0a9d6a9e176acba3a8753caa2bd8b14d6bc622fb
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jun 26 16:24:28 2017 -0400

            PR c++/81204 - parse error with dependent template-name
    
            * parser.c (cp_parser_lookup_name): Disqualify function templates
            after lookup.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2ff6afd..e0a6c8b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -25813,11 +25813,22 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
        decl = NULL_TREE;
 
       if (!decl)
-       /* 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, prefer_type_arg (tag_type, is_template),
-                                /*nonclass=*/0,
-                                /*block_p=*/true, is_namespace, 0);
+       {
+         /* Look it up in the enclosing context.  */
+         decl = lookup_name_real (name, prefer_type_arg (tag_type),
+                                  /*nonclass=*/0,
+                                  /*block_p=*/true, is_namespace, 0);
+         /* DR 141 says when looking for a template-name after -> or ., only
+            consider class templates.  */
+         if (decl && is_template && !DECL_TYPE_TEMPLATE_P (decl))
+           {
+             tree d = decl;
+             if (is_overloaded_fn (d))
+               d = get_first_fn (d);
+             if (DECL_P (d) && !DECL_CLASS_SCOPE_P (d))
+               decl = NULL_TREE;
+           }
+       }
       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.  */
diff --git a/gcc/testsuite/g++.dg/template/lookup10.C 
b/gcc/testsuite/g++.dg/template/lookup10.C
new file mode 100644
index 0000000..fa90af4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/lookup10.C
@@ -0,0 +1,12 @@
+// PR c++/81204
+
+namespace std {
+  template<typename, typename> struct set { };
+}
+using namespace std;
+
+template <int I, typename Result>
+inline void set(Result & res)
+{
+    res.template set<I>();
+}
commit bb0c81aecf7ac956e770e4eb6eca02f4fe6fd686
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jun 26 16:52:57 2017 -0400

            PR c++/54769 - wrong lookup of dependent template-name.
    
            * parser.c (cp_parser_template_name): Handle dependent object type.
            (cp_parser_nested_name_specifier_opt): Make template_keyword_p a
            parameter.
            (cp_parser_id_expression): Pass it.
            (cp_parser_diagnose_invalid_type_name): Handle TEMPLATE_ID_EXPR.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 246af76..c9fc284 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2039,7 +2039,7 @@ static cp_expr cp_parser_id_expression
 static cp_expr cp_parser_unqualified_id
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_nested_name_specifier_opt
-  (cp_parser *, bool, bool, bool, bool);
+  (cp_parser *, bool, bool, bool, bool, bool = false);
 static tree cp_parser_nested_name_specifier
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_qualifying_entity
@@ -3253,6 +3253,10 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, 
tree id,
            error_at (location_of (id),
                      "%qE in namespace %qE does not name a template type",
                      id, parser->scope);
+         else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
+           error_at (location_of (id),
+                     "%qE in namespace %qE does not name a template type",
+                     TREE_OPERAND (id, 0), parser->scope);
          else
            error_at (location_of (id),
                      "%qE in namespace %qE does not name a type",
@@ -3296,6 +3300,10 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, 
tree id,
            error_at (location_of (id),
                      "%qE in %q#T does not name a template type",
                      id, parser->scope);
+         else if (TREE_CODE (id) == TEMPLATE_ID_EXPR)
+           error_at (location_of (id),
+                     "%qE in %q#T does not name a template type",
+                     TREE_OPERAND (id, 0), parser->scope);
          else
            error_at (location_of (id),
                      "%qE in %q#T does not name a type",
@@ -5420,16 +5428,21 @@ cp_parser_id_expression (cp_parser *parser,
 
   /* Look for the optional `::' operator.  */
   global_scope_p
-    = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)
-       != NULL_TREE);
+    = (!template_keyword_p
+       && (cp_parser_global_scope_opt (parser,
+                                      /*current_scope_valid_p=*/false)
+          != NULL_TREE));
+
   /* Look for the optional nested-name-specifier.  */
   nested_name_specifier_p
     = (cp_parser_nested_name_specifier_opt (parser,
                                            /*typename_keyword_p=*/false,
                                            check_dependency_p,
                                            /*type_p=*/false,
-                                           declarator_p)
+                                           declarator_p,
+                                           template_keyword_p)
        != NULL_TREE);
+
   /* If there is a nested-name-specifier, then we are looking at
      the first qualified-id production.  */
   if (nested_name_specifier_p)
@@ -5874,7 +5887,8 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
                                     bool typename_keyword_p,
                                     bool check_dependency_p,
                                     bool type_p,
-                                    bool is_declaration)
+                                    bool is_declaration,
+                                    bool template_keyword_p /* = false */)
 {
   bool success = false;
   cp_token_position start = 0;
@@ -5892,7 +5906,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
       tree new_scope;
       tree old_scope;
       tree saved_qualifying_scope;
-      bool template_keyword_p;
 
       /* Spot cases that cannot be the beginning of a
         nested-name-specifier.  */
@@ -5967,8 +5980,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
         first time through the loop.  */
       if (success)
        template_keyword_p = cp_parser_optional_template_keyword (parser);
-      else
-       template_keyword_p = false;
 
       /* Save the old scope since the name lookup we are about to do
         might destroy it.  */
@@ -15861,15 +15872,19 @@ cp_parser_template_name (cp_parser* parser,
         no point in doing name-lookup, so we just return IDENTIFIER.
         But, if the qualifying scope is non-dependent then we can
         (and must) do name-lookup normally.  */
-      if (template_keyword_p
-         && (!parser->scope
-             || (TYPE_P (parser->scope)
-                 && dependent_type_p (parser->scope))))
+      if (template_keyword_p)
        {
-         /* We're optimizing away the call to cp_parser_lookup_name, but we
-            still need to do this.  */
-         parser->context->object_type = NULL_TREE;
-         return identifier;
+         tree scope = (parser->scope ? parser->scope
+                       : parser->context->object_type);
+         if (scope && TYPE_P (scope)
+             && (!CLASS_TYPE_P (scope)
+                 || (check_dependency_p && dependent_type_p (scope))))
+           {
+             /* We're optimizing away the call to cp_parser_lookup_name, but
+                we still need to do this.  */
+             parser->context->object_type = NULL_TREE;
+             return identifier;
+           }
        }
     }
 
@@ -15882,6 +15897,11 @@ cp_parser_template_name (cp_parser* parser,
                                /*ambiguous_decls=*/NULL,
                                token->location);
 
+  /* If the lookup failed and we got the 'template' keyword, believe it.  */
+  if (decl == error_mark_node && template_keyword_p
+      && processing_template_decl)
+    return identifier;
+
   decl = strip_using_decl (decl);
 
   /* If DECL is a template, then the name was a template-name.  */
diff --git a/gcc/testsuite/g++.dg/template/lookup11.C 
b/gcc/testsuite/g++.dg/template/lookup11.C
new file mode 100644
index 0000000..203460e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/lookup11.C
@@ -0,0 +1,11 @@
+// PR c++/81026
+
+namespace std {
+  template<class> struct extent;
+}
+using namespace std;
+
+template <class T>
+struct S {
+  void f() { T().template extent<42>(); }
+};
commit 2f4e3c6bd0be31008674c8e56a9c41ddacc3924b
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jun 27 02:19:33 2017 -0400

            Make the TEMPLATE_ID_EXPR location a range.
    
            * parser.c (cp_parser_template_id): Use the range location on the
            TEMPLATE_ID_EXPR.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e0a6c8b..246af76 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15522,17 +15522,17 @@ cp_parser_template_id (cp_parser *parser,
 
   /* If the next token corresponds to a template-id, there is no need
      to reparse it.  */
-  next_token = cp_lexer_peek_token (parser->lexer);
-  if (next_token->type == CPP_TEMPLATE_ID)
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  if (token->type == CPP_TEMPLATE_ID)
     {
       cp_lexer_consume_token (parser->lexer);
-      return saved_checks_value (next_token->u.tree_check_value);
+      return saved_checks_value (token->u.tree_check_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
+  if ((token->type != CPP_NAME && token->keyword != RID_OPERATOR)
+      || (token->type == CPP_NAME
          && !cp_parser_nth_token_starts_template_argument_list_p
               (parser, 2)))
     {
@@ -15623,9 +15623,19 @@ cp_parser_template_id (cp_parser *parser,
       arguments = cp_parser_enclosed_template_argument_list (parser);
     }
 
+  /* Set the location to be of the form:
+     template-name < template-argument-list [opt] >
+     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     with caret == start at the start of the template-name,
+     ranging until the closing '>'.  */
+  location_t finish_loc
+    = get_finish (cp_lexer_previous_token (parser->lexer)->location);
+  location_t combined_loc
+    = make_location (token->location, token->location, finish_loc);
+
   /* Build a representation of the specialization.  */
   if (identifier_p (templ))
-    template_id = build_min_nt_loc (next_token->location,
+    template_id = build_min_nt_loc (combined_loc,
                                    TEMPLATE_ID_EXPR,
                                    templ, arguments);
   else if (DECL_TYPE_TEMPLATE_P (templ)
@@ -15652,7 +15662,7 @@ cp_parser_template_id (cp_parser *parser,
     {
       template_id = lookup_template_variable (templ, arguments);
       if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR)
-       SET_EXPR_LOCATION (template_id, next_token->location);
+       SET_EXPR_LOCATION (template_id, combined_loc);
     }
   else
     {
@@ -15664,7 +15674,7 @@ cp_parser_template_id (cp_parser *parser,
 
       template_id = lookup_template_function (templ, arguments);
       if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR)
-       SET_EXPR_LOCATION (template_id, next_token->location);
+       SET_EXPR_LOCATION (template_id, combined_loc);
     }
 
   /* If parsing tentatively, replace the sequence of tokens that makes
@@ -15680,20 +15690,8 @@ cp_parser_template_id (cp_parser *parser,
           && cp_parser_parsing_tentatively (parser)
           && parser->in_declarator_p))
     {
-      cp_token *token = cp_lexer_token_at (parser->lexer, start_of_id);
-
       /* Reset the contents of the START_OF_ID token.  */
       token->type = CPP_TEMPLATE_ID;
-
-      /* Update the location to be of the form:
-          template-name < template-argument-list [opt] >
-          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        with caret == start at the start of the template-name,
-        ranging until the closing '>'.  */
-      location_t finish_loc
-       = get_finish (cp_lexer_previous_token (parser->lexer)->location);
-      location_t combined_loc
-       = make_location (token->location, token->location, finish_loc);
       token->location = combined_loc;
 
       /* We must mark the lookup as kept, so we don't throw it away on
commit 8938ec573f84ed013fc9f4721f17e73a0bfc82e1
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jun 27 14:05:16 2017 -0400

            PR c++/45976 - error with ::template in declarator.
    
            * pt.c (resolve_typename_type): Fix TEMPLATE_ID_EXPR handling.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 957d229..b060a19 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -24624,26 +24624,38 @@ resolve_typename_type (tree type, bool only_current_p)
   
   /* For a TYPENAME_TYPE like "typename X::template Y<T>", we want to
      find a TEMPLATE_DECL.  Otherwise, we want to find a TYPE_DECL.  */
+  tree fullname = TYPENAME_TYPE_FULLNAME (type);
   if (!decl)
     /*nop*/;
-  else if (identifier_p (TYPENAME_TYPE_FULLNAME (type))
+  else if (identifier_p (fullname)
           && TREE_CODE (decl) == TYPE_DECL)
     {
       result = TREE_TYPE (decl);
       if (result == error_mark_node)
        result = NULL_TREE;
     }
-  else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR
+  else if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR
           && DECL_CLASS_TEMPLATE_P (decl))
     {
-      tree tmpl;
-      tree args;
       /* Obtain the template and the arguments.  */
-      tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0);
-      args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1);
+      tree tmpl = TREE_OPERAND (fullname, 0);
+      if (TREE_CODE (tmpl) == IDENTIFIER_NODE)
+       {
+         /* We get here with a plain identifier because a previous tentative
+            parse of the nested-name-specifier as part of a ptr-operator saw
+            ::template X<A>.  The use of ::template is necessary in a
+            ptr-operator, but wrong in a declarator-id.
+
+            [temp.names]: In a qualified-id of a declarator-id, the keyword
+            template shall not appear at the top level.  */
+         pedwarn (EXPR_LOC_OR_LOC (fullname, input_location), OPT_Wpedantic,
+                  "keyword %<template%> not allowed in declarator-id");
+         tmpl = decl;
+       }
+      tree args = TREE_OPERAND (fullname, 1);
       /* Instantiate the template.  */
       result = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE,
-                                     /*entering_scope=*/0,
+                                     /*entering_scope=*/true,
                                      tf_error | tf_user);
       if (result == error_mark_node)
        result = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/template/template-keyword1.C 
b/gcc/testsuite/g++.dg/template/template-keyword1.C
new file mode 100644
index 0000000..0f928a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/template-keyword1.C
@@ -0,0 +1,15 @@
+// PR c++/45976
+
+template<int a>
+struct A {
+    static const int value;
+   
+    template<int b>
+    struct B {
+        static const int value;
+    };
+};
+
+template<int a>
+template<int b>
+const int A<a>::template B<b>::value = 0; // { dg-error "keyword .template" }
commit bef4c2fc9c89825503ddbff062544dd7d2582ac2
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Jun 28 12:41:34 2017 -0400

            PR c++/55639 - partial specialization with ::template
    
            * parser.c (cp_parser_class_head): Handle ::template.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c9fc284..bd99c05 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -22602,6 +22602,9 @@ cp_parser_class_head (cp_parser* parser,
                                           /*is_declaration=*/false);
   /* If there was a nested-name-specifier, then there *must* be an
      identifier.  */
+
+  cp_token *bad_template_keyword = NULL;
+
   if (nested_name_specifier)
     {
       type_start_token = cp_lexer_peek_token (parser->lexer);
@@ -22623,6 +22626,8 @@ cp_parser_class_head (cp_parser* parser,
         class-name is a template-id; if we looked for the
         template-name first we would stop after the template-name.  */
       cp_parser_parse_tentatively (parser);
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
+       bad_template_keyword = cp_lexer_consume_token (parser->lexer);
       type = cp_parser_class_name (parser,
                                   /*typename_keyword_p=*/false,
                                   /*template_keyword_p=*/false,
@@ -22742,6 +22747,12 @@ cp_parser_class_head (cp_parser* parser,
     {
       tree scope;
 
+      if (bad_template_keyword)
+       /* [temp.names]: in a qualified-id formed by a class-head-name, the
+          keyword template shall not appear at the top level.  */
+       pedwarn (bad_template_keyword->location, OPT_Wpedantic,
+                "keyword %<template%> not allowed in class-head-name");
+
       /* Reject typedef-names in class heads.  */
       if (!DECL_IMPLICIT_TYPEDEF_P (type))
        {
diff --git a/gcc/testsuite/g++.dg/template/partial-specialization8.C 
b/gcc/testsuite/g++.dg/template/partial-specialization8.C
new file mode 100644
index 0000000..e3ffe3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/partial-specialization8.C
@@ -0,0 +1,19 @@
+// PR c++/55639
+
+template <int number>
+struct SomeClass
+{
+  SomeClass() { }
+
+  template <typename E, int number2>
+  struct Fun {
+    static void
+    fun() { }
+  };
+};
+
+template <int number>
+template <typename E>
+struct SomeClass<number>::template Fun<E, 0> { // { dg-error "template" }
+  static void fun() { }
+};

Reply via email to