[C++ PATCH] Change order of tentative parsing in cp_parser_postfix_dot_deref_expression (PR c++/35138)

Jakub Jelinek jakub@redhat.com
Tue Feb 12 18:07:00 GMT 2008


Hi!

To fix PR32384, I have changed 3 months ago
cp_parser_postfix_dot_deref_expression, if postfix-expression is dependent,
to parse it tentatively as pseudo-dtor first and if that fails do what it
did before, parse as id-expression.  Unfortunately it turns out that even
tentative parsing isn't silent and sometimes emits errors unconditionally,
and limiting the PR20293 errors to definitive parse or when committed to
tentative parse resulted in many regressions.

So, this patch instead changes the order of tentative parses.
It parses as pseudo-dtor-name first only if scope is known to be scalar.
If not dependent, it is parsed as id-expression.
If dependent, it is parsed tentatively first as id-expression, if that
fails tentatively as pseudo-dtor-name and if both fail, parsed definitely
again as id-expression to get all diagnostics (because id-expression is
much more common than pseudo-dtors).  AFAIK the ambiguous decl errors
that are issued even when parsing tentatively set ambiguous_p on cp_token,
so there shouldn't be any duplicate errors.

Regtested on x86_64-linux, all pseudodtor*.C testcases keep working
and the new testcase works too.

Ok for trunk?

2008-02-12  Jakub Jelinek  <jakub@redhat.com>

	PR c++/35138
	* parser.c (cp_parser_postfix_dot_deref_expression): If
	postfix-expression is dependent, parse as id-expression tentatively
	first and as pseudo-dtor only if the parsing failed.

	* g++.dg/template/member8.C: New test.

--- gcc/cp/parser.c.jj	2008-02-12 14:49:55.000000000 +0100
+++ gcc/cp/parser.c	2008-02-12 18:12:13.000000000 +0100
@@ -4812,6 +4812,7 @@ cp_parser_postfix_dot_deref_expression (
   bool dependent_p;
   bool pseudo_destructor_p;
   tree scope = NULL_TREE;
+  bool template_p = false;
 
   /* If this is a `->' operator, dereference the pointer.  */
   if (token_type == CPP_DEREF)
@@ -4862,10 +4863,8 @@ cp_parser_postfix_dot_deref_expression (
   pseudo_destructor_p = false;
 
   /* If the SCOPE is a scalar type, then, if this is a valid program,
-     we must be looking at a pseudo-destructor-name.  If POSTFIX_EXPRESSION
-     is type dependent, it can be pseudo-destructor-name or something else.
-     Try to parse it as pseudo-destructor-name first.  */
-  if ((scope && SCALAR_TYPE_P (scope)) || dependent_p)
+     we must be looking at a pseudo-destructor-name.  */
+  if ((scope && SCALAR_TYPE_P (scope)))
     {
       tree s;
       tree type;
@@ -4874,12 +4873,7 @@ cp_parser_postfix_dot_deref_expression (
       /* Parse the pseudo-destructor-name.  */
       s = NULL_TREE;
       cp_parser_pseudo_destructor_name (parser, &s, &type);
-      if (dependent_p
-	  && (cp_parser_error_occurred (parser)
-	      || TREE_CODE (type) != TYPE_DECL
-	      || !SCALAR_TYPE_P (TREE_TYPE (type))))
-	cp_parser_abort_tentative_parse (parser);
-      else if (cp_parser_parse_definitely (parser))
+      if (cp_parser_parse_definitely (parser))
 	{
 	  pseudo_destructor_p = true;
 	  postfix_expression
@@ -4892,16 +4886,62 @@ cp_parser_postfix_dot_deref_expression (
     {
       /* If the SCOPE is not a scalar type, we are looking at an
 	 ordinary class member access expression, rather than a
-	 pseudo-destructor-name.  */
-      bool template_p;
+	 pseudo-destructor-name.  If the SCOPE is dependent, it
+	 might be ordinary class member access expression, but
+	 also pseudo-destructor-name.  Try to parse it first as
+	 ordinary class member access expression, if that fails
+	 as pseudo-destructor-name.  */
+      if (dependent_p)
+	cp_parser_parse_tentatively (parser);
+
       /* Parse the id-expression.  */
-      name = (cp_parser_id_expression
+      name = cp_parser_id_expression
 	      (parser,
 	       cp_parser_optional_template_keyword (parser),
 	       /*check_dependency_p=*/true,
 	       &template_p,
 	       /*declarator_p=*/false,
-	       /*optional_p=*/false));
+	       /*optional_p=*/false);
+
+      if (dependent_p)
+	{
+	  if (cp_parser_error_occurred (parser))
+	    {
+	      tree s;
+	      tree type;
+
+	      cp_parser_abort_tentative_parse (parser);
+	      cp_parser_parse_tentatively (parser);
+	      /* Parse the pseudo-destructor-name.  */
+	      s = NULL_TREE;
+	      cp_parser_pseudo_destructor_name (parser, &s, &type);
+	      if (!cp_parser_error_occurred (parser))
+		{
+		  cp_parser_parse_definitely (parser);
+		  pseudo_destructor_p = true;
+		  postfix_expression
+		    = finish_pseudo_destructor_expr (postfix_expression,
+						     s, TREE_TYPE (type));
+		}
+	      else
+		{
+		  cp_parser_abort_tentative_parse (parser);
+		  name = cp_parser_id_expression
+			   (parser,
+			    cp_parser_optional_template_keyword (parser),
+			    /*check_dependency_p=*/true,
+			    &template_p,
+			    /*declarator_p=*/false,
+			    /*optional_p=*/false);
+		}
+	    }
+	  else
+	    cp_parser_parse_definitely (parser);
+	}
+    }
+
+  if (!pseudo_destructor_p)
+    {
       /* 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;
--- gcc/testsuite/g++.dg/template/member8.C.jj	2008-02-12 18:32:14.000000000 +0100
+++ gcc/testsuite/g++.dg/template/member8.C	2008-02-12 18:19:23.000000000 +0100
@@ -0,0 +1,25 @@
+// PR c++/35138
+// { dg-do compile }
+
+namespace N1 { struct A { }; }
+namespace N2 { struct A { }; }
+using namespace N1;
+using namespace N2;
+
+template <typename T> int
+foo (T const &t)
+{
+  return t.A;
+}
+
+struct B
+{
+  int A;
+};
+
+int
+main ()
+{
+  B b;
+  foo (b);
+}

	Jakub



More information about the Gcc-patches mailing list