This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] [PR8856] A conversion-function-id cannot be a template-name (regression on trunk)


Hello Mark,

in the new parser, a conversion-function-id (CFI) is considered among the
productions for a template-name (in the comment, this is reported as a defect
of the C++ standard). But this is not true: in fact, a CFI can never be part of
a template-id. Consider the following code:

-------------------------------------------------------
struct K1 {};
template <class> struct K2 {};

struct A {
   template <class U> operator U() { return U(); }
};

void foo(void)
{
  A a;
  a.operator K1<int>();  // #1
  a.operator K2<int>();  // #2
}
-------------------------------------------------------

It's clear that #1 is ill-formed while #2 is correct. In fact, the template
argument list refers to the template name "K1" or "K2", not to the whole CFI.
If the CFI is a template (like in this case), it must have only one parameter,
which is the type it's converting to. And this parameter is not specified with
the usual template argument list syntax, but simply by putting the type name
after the keyword 'operator'. Thus, "operator K2<int>" is the whole CFI, and
"K2<int>" is a type name the CFI is converting to (and that happens to be a
template-id).

In other words, there is no way to provide an explicit argument list for a
template conversion function. This is stated in 14.5.2/5: "because the explicit
template argument list follows the function template name, and because
conversion member function templates and constructor member function templates
are called without using a function name, there is no way to provide an
explicit template argument list for these function templates.". Because of this
bug, we were accepting illegal code such as #1, or the even funnier "a.operator
double<int>();". This is a regression on the trunk.

The testcase g++.old-deja/g++.pt/explicit83.C actually checks exactly for this
non-feature (explicit template arguments for a templated conversion function),
so it's totally bogus to me. A template conversion function declared as:
------------------------------------------
template <class T> operator int();
------------------------------------------
could even be rejected at declaration time because it's ill-formed. This is DR
264 and I strongly agree with it. For now, my patch simply removes this
testcase.

This does not apply to operator-function-id. In fact, they follow the normal
template syntax, as in you can say "a.operator+<double>(3.0f)", and the whole
"operator+ <double>" is an operator-function-id which is a template-id.

Fixed thus. There is an additional hunk which checks for invalid template
argument lists after built-in types, which allows a beautiful error message
such as "'double' is not a template name" for the aforementioned line. Tested
on i686-pc-linux-gnu, no new regressions. OK for mainline?

Gaby: part of this bug is a regression on the 3.3 branch as well (only if the
postfix-expression is qualified, as in 'a.A::operator double<int>'). Alas, a
fix for the branch would involve tweaking with the old parser, which I'm not
familiar with. Given that this is just an accepts-invalid, and the additional
template argument list is silently ignored by the compiler without
side-effects, my opinion is that we can go with WONTFIX for the branch.

Thanks,
Giovanni Bajo




2004-01-15  Giovanni Bajo  <giovannibajo@gcc.gnu.org>

        PR c++/8856
        * parser.c (cp_parser_template_name): Don't try to parse a
        conversion-function-id, as it cannot be a template-name.
        (cp_parser_simple_type_specifier): Check for invalid template-ids
        even after a built-in type.

2004-01-15  Giovanni Bajo  <giovannibajo@gcc.gnu.org>

        PR c++/8856
        * g++.dg/parse/casting-operator2.C: New test.
        * g++.old-deja/g++.pt/explicit83.C: Remove.



Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.152
diff -c -3 -p -r1.152 parser.c
*** parser.c    13 Jan 2004 00:44:50 -0000      1.152
--- parser.c    14 Jan 2004 23:18:18 -0000
*************** cp_parser_template_id (cp_parser *parser
*** 7882,7891 ****
     template-name:
       identifier
       operator-function-id
-      conversion-function-id

     A defect report has been filed about this issue.

     If TEMPLATE_KEYWORD_P is true, then we have just seen the
     `template' keyword, in a construction like:

--- 7882,7900 ----
     template-name:
       identifier
       operator-function-id

     A defect report has been filed about this issue.

+    A conversion-function-id cannot be a template name because they cannot
+    be part of a template-id. In fact, looking at this code:
+
+    a.operator K<int>()
+
+    the conversion-function-id is "operator K<int>", and K<int> is a type-id.
+    It is impossible to call a templated conversion-function-id with an
+    explicit argument list, since the only allowed template parameter is
+    the type to which it is converting.
+
     If TEMPLATE_KEYWORD_P is true, then we have just seen the
     `template' keyword, in a construction like:

*************** cp_parser_template_name (cp_parser* pars
*** 7922,7928 ****
        identifier = cp_parser_operator_function_id (parser);
        /* If that didn't work, try a conversion-function-id.  */
        if (!cp_parser_parse_definitely (parser))
!       identifier = cp_parser_conversion_function_id (parser);
      }
    /* Look for the identifier.  */
    else
--- 7931,7940 ----
        identifier = cp_parser_operator_function_id (parser);
        /* If that didn't work, try a conversion-function-id.  */
        if (!cp_parser_parse_definitely (parser))
!         {
!         cp_parser_error (parser, "expected template-name");
!         return error_mark_node;
!         }
      }
    /* Look for the identifier.  */
    else
*************** cp_parser_simple_type_specifier (cp_pars
*** 8705,8710 ****
--- 8717,8728 ----

        /* Consume the token.  */
        id = cp_lexer_consume_token (parser->lexer)->value;
+
+       /* There is no valid C++ program where a non-template type is
+        followed by a "<".  That usually indicates that the user thought
+        that the type was a template.  */
+       cp_parser_check_for_invalid_template_id (parser, type);
+
        return identifier_p ? id : TYPE_NAME (type);
      }



// { dg-do compile }
// Contributed by Martin Loewis <loewis at informatik dot hu-berlin dot de>
// PR c++/8856: Make sure template conversion operators are not parsed as
//   template names.

struct K {};
template <bool> struct K2 {};

template <class T> struct A {
  template <class U> operator U() { return U(); }
};

int main() {
  A<double> a;

  (void)a.operator int();
  (void)a.operator double();
  (void)a.operator K2<true>();
  (void)a.A<double>::operator int();
  (void)a.A<double>::operator double();
  (void)a.A<double>::operator K2<true>();

  (void)a.operator double<int>();             // { dg-error "not a template" }
  (void)a.operator K<int>();                  // { dg-error "not a template" }
  (void)a.A<double>::operator double<int>();  // { dg-error "not a template" }
  (void)a.A<double>::operator K<int>();       // { dg-error "not a template" }
}



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]