Patchwork [c++] fix PR 46890, parsing regression

login
register
mail settings
Submitter Nathan Froyd
Date Jan. 24, 2011, 5:49 p.m.
Message ID <20110124174940.GJ6247@codesourcery.com>
Download mbox | patch
Permalink /patch/80222/
State New
Headers show

Comments

Nathan Froyd - Jan. 24, 2011, 5:49 p.m.
On Fri, Jan 21, 2011 at 11:21:03AM -0500, Jason Merrill wrote:
> On 01/21/2011 09:07 AM, Nathan Froyd wrote:
>> On Wed, Jan 05, 2011 at 02:39:58PM -0500, Jason Merrill wrote:
>>> How about keyword_is_decl_specifier?
>>
>> That's a bit cryptic.  Do you mean adding keyword_is_decl_specifier to
>> c-family?
>
> Yes, that's what I had in mind.  Let's have a predicate that does the  
> test we want with a name that accurately describes it.

OK, how about this patch?  It includes Jakub's proposed testcase from
the PR.  Tested bootstrap, g++ and libstdc++.

-Nathan

gcc/c-family/
	PR c++/46890
	* c-common.h (keyword_is_decl_specifier): Declare.
	* c-common.c (keyword_is_decl_specifier): Define.
	(keyword_is_function_specifier): New function.

gcc/cp/
	PR c++/46890
	* parser.c (cp_parser_class_specifier): Fix setting of
	want_semicolon.

gcc/testsuite/
	PR c++/46890
	* g++.dg/parser/semicolon3.C: Adjust.
	* g++.dg/parser/semicolon4.C: New testcase.
	* g++.dg/pr46890.C: New testcase.
Joseph S. Myers - Jan. 26, 2011, 12:25 a.m.
On Mon, 24 Jan 2011, Nathan Froyd wrote:

> +/* Return true if KEYWORD names a decl-specifier [dcl.spec] or a
> +   declaration-specifier (C99 6.7).  */
> +
> +bool
> +keyword_is_decl_specifier (enum rid keyword)
> +{
> +  if (keyword_is_storage_class_specifier (keyword)
> +      || keyword_is_type_qualifier (keyword)
> +      || keyword_is_function_specifier (keyword))
> +    return true;

Did you mean to exclude type specifiers here?  (If you include them, of 
course, by using keyword_begins_type_specifier you'd be making this say 
whether a keyword begins a decl-specifier rather than whether it *is* 
one.)
Nathan Froyd - Jan. 26, 2011, 12:58 a.m.
On Wed, Jan 26, 2011 at 12:25:31AM +0000, Joseph S. Myers wrote:
> On Mon, 24 Jan 2011, Nathan Froyd wrote:
> > +/* Return true if KEYWORD names a decl-specifier [dcl.spec] or a
> > +   declaration-specifier (C99 6.7).  */
> > +
> > +bool
> > +keyword_is_decl_specifier (enum rid keyword)
> > +{
> > +  if (keyword_is_storage_class_specifier (keyword)
> > +      || keyword_is_type_qualifier (keyword)
> > +      || keyword_is_function_specifier (keyword))
> > +    return true;
> 
> Did you mean to exclude type specifiers here?

I did mean to exclude them.  This is not exactly in line with the
language specifications, but it is appropriate for how this function is
used during parsing.  Better suggestions for the name welcome.

-Nathan
Nathan Froyd - Jan. 31, 2011, 2:35 p.m.
On Mon, Jan 24, 2011 at 09:49:41AM -0800, Nathan Froyd wrote:
> On Fri, Jan 21, 2011 at 11:21:03AM -0500, Jason Merrill wrote:
> > Yes, that's what I had in mind.  Let's have a predicate that does the  
> > test we want with a name that accurately describes it.
> 
> OK, how about this patch?  It includes Jakub's proposed testcase from
> the PR.  Tested bootstrap, g++ and libstdc++.

Ping.  http://gcc.gnu.org/ml/gcc-patches/2011-01/msg01667.html

-Nathan
Jason Merrill - Feb. 3, 2011, 4:54 p.m.
OK.

Jason

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 2156fa8..3e46019 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -9653,4 +9653,42 @@  keyword_is_storage_class_specifier (enum rid keyword)
     }
 }
 
+/* Return true if KEYWORD names a function-specifier [dcl.fct.spec].  */
+
+static bool
+keyword_is_function_specifier (enum rid keyword)
+{
+  switch (keyword)
+    {
+    case RID_INLINE:
+    case RID_VIRTUAL:
+    case RID_EXPLICIT:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Return true if KEYWORD names a decl-specifier [dcl.spec] or a
+   declaration-specifier (C99 6.7).  */
+
+bool
+keyword_is_decl_specifier (enum rid keyword)
+{
+  if (keyword_is_storage_class_specifier (keyword)
+      || keyword_is_type_qualifier (keyword)
+      || keyword_is_function_specifier (keyword))
+    return true;
+
+  switch (keyword)
+    {
+    case RID_TYPEDEF:
+    case RID_FRIEND:
+    case RID_CONSTEXPR:
+      return true;
+    default:
+      return false;
+    }
+}
+
 #include "gt-c-family-c-common.h"
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 05456d3..406def9 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -741,6 +741,7 @@  extern bool float_const_decimal64_p (void);
 extern bool keyword_begins_type_specifier (enum rid);
 extern bool keyword_is_storage_class_specifier (enum rid);
 extern bool keyword_is_type_qualifier (enum rid);
+extern bool keyword_is_decl_specifier (enum rid);
 
 #define c_sizeof(LOC, T)  c_sizeof_or_alignof_type (LOC, T, true, 1)
 #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 41f82ac..4a6a8d0 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -16998,18 +16998,15 @@  cp_parser_class_specifier (cp_parser* parser)
 	   class Z { }
 	   static const <type> var = ...;  */
       case CPP_KEYWORD:
-	if (keyword_is_storage_class_specifier (token->keyword)
-	    || keyword_is_type_qualifier (token->keyword))
+	if (keyword_is_decl_specifier (token->keyword))
 	  {
 	    cp_token *lookahead = cp_lexer_peek_nth_token (parser->lexer, 2);
 
-	    if (lookahead->type == CPP_KEYWORD
-		&& !keyword_begins_type_specifier (lookahead->keyword))
-	      want_semicolon = false;
-	    else if (lookahead->type == CPP_NAME)
-	      /* Handling user-defined types here would be nice, but
-		 very tricky.  */
-	      want_semicolon = false;
+	    /* Handling user-defined types here would be nice, but very
+	       tricky.  */
+	    want_semicolon
+	      = (lookahead->type == CPP_KEYWORD
+		 && keyword_begins_type_specifier (lookahead->keyword));
 	  }
 	break;
       default:
diff --git a/gcc/testsuite/g++.dg/parse/semicolon3.C b/gcc/testsuite/g++.dg/parse/semicolon3.C
index a119ef4..bc43b48 100644
--- a/gcc/testsuite/g++.dg/parse/semicolon3.C
+++ b/gcc/testsuite/g++.dg/parse/semicolon3.C
@@ -62,6 +62,48 @@  autotest (void)
   return ok10.a;
 }
 
+struct OK11
+{
+  int a;
+} // no complaints
+  const *ok11_var;
+
+struct OK12
+{
+  int a;
+} // no complaints
+  const &ok12_var = *(new OK12());
+
+struct OK13
+{
+  int a;
+} // no complaints
+  static *ok13_var;
+
+class OK14
+{
+  struct OK14sub
+  {
+    int a;
+  } // no complaints
+    static &ok14_var;
+};
+
+class OK15
+{
+  int a;
+} typedef tOK15;
+
+class OK16
+{
+  int a;
+} typedef *pOK16;
+
+class OK17
+{
+  int a;
+} typedef &rOK16;
+
 struct E1
 {
   int a;
@@ -196,6 +238,13 @@  class E17
     mutable int i;
 } // { dg-error "after class definition" }
 
+class E18
+{
+  int a;
+} // { dg-error "after class definition" }
+
+typedef int E18int;
+
 /* This was the original test from the PR.  */
 
 class C0
diff --git a/gcc/testsuite/g++.dg/parse/semicolon4.C b/gcc/testsuite/g++.dg/parse/semicolon4.C
new file mode 100644
index 0000000..adba7a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/semicolon4.C
@@ -0,0 +1,37 @@ 
+// PR c++/46890
+// { dg-do compile }
+
+struct OK1
+{
+  int i;
+} const *ok1_var;		// No complains
+
+struct OK2;
+extern OK2 ok2a_var;
+
+struct OK2
+{
+  int i;
+} const &ok2_var = ok2a_var;	// No complains
+
+struct OK3
+{
+  int i;
+} volatile (ok3_var);		// No complains
+
+struct E1
+{
+  int i;
+} const;			// { dg-error "qualifiers can only be specified for objects and functions" }
+
+void foo (
+struct E2
+{				// { dg-error "types may not be defined in parameter types" }
+  int i;
+} volatile);
+
+void bar (
+struct E3
+{				// { dg-error "types may not be defined in parameter types" }
+  int i;
+} const, int);
diff --git a/gcc/testsuite/g++.dg/pr46890.C b/gcc/testsuite/g++.dg/pr46890.C
new file mode 100644
index 0000000..3ecef5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr46890.C
@@ -0,0 +1,6 @@ 
+// PR c++/46890
+// { dg-do compile }
+
+struct MdatResource {
+const char *mdatAlloc;
+} const *_resource;