Committed as obvious.

The patch fixes PR fortran/90988 where a less than
informative error is emitted for invalid code with
a PUBLIC specification statement.  As a bonus fix
parsing errors for PRIVATE and PROTECTED as pointed
out in https://gcc.gnu.org/ml/fortran/2019-06/msg00144.html

2019-06-24  Steven G. Kargl  <ka...@gcc.gnu.org>

        PR Fortran/90988
        * decl.c (access_attr_decl): Use temporary variable to reduce
        unreadability of code.  Normalize jumping to return.
        (gfc_match_protected): Fix parsing error.  Add comments to 
        explain code.  Remove dead code.
        (gfc_match_private): Use temporary variable to reduce unreadability 
        of code. Fix parsing error.  Move code to test for blank PRIVATE.
        Remove dead code.
        (gfc_match_public): Move code to test for blank PUBLIC.  Fix
        parsing error.  Remove dead code.

2019-06-24  Steven G. Kargl  <ka...@gcc.gnu.org>

        PR Fortran/90988
        * gfortran.dg/pr90988_1.f90: New test.
        * gfortran.dg/pr90988_2.f90: Ditto.
        * gfortran.dg/pr90988_3.f90: Ditto.

-- 
Steve
Index: gcc/fortran/decl.c
===================================================================
--- gcc/fortran/decl.c	(revision 272666)
+++ gcc/fortran/decl.c	(working copy)
@@ -8788,6 +8788,7 @@ access_attr_decl (gfc_statement st)
   gfc_symbol *sym, *dt_sym;
   gfc_intrinsic_op op;
   match m;
+  gfc_access access = (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
 
   if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
     goto done;
@@ -8798,7 +8799,7 @@ access_attr_decl (gfc_statement st)
       if (m == MATCH_NO)
 	goto syntax;
       if (m == MATCH_ERROR)
-	return MATCH_ERROR;
+	goto done;
 
       switch (type)
 	{
@@ -8818,18 +8819,12 @@ access_attr_decl (gfc_statement st)
 	      && sym->attr.flavor == FL_UNKNOWN)
 	    sym->attr.flavor = FL_PROCEDURE;
 
-	  if (!gfc_add_access (&sym->attr,
-			       (st == ST_PUBLIC)
-			       ? ACCESS_PUBLIC : ACCESS_PRIVATE,
-			       sym->name, NULL))
-	    return MATCH_ERROR;
+	  if (!gfc_add_access (&sym->attr, access, sym->name, NULL))
+	    goto done;
 
 	  if (sym->attr.generic && (dt_sym = gfc_find_dt_in_generic (sym))
-	      && !gfc_add_access (&dt_sym->attr,
-				  (st == ST_PUBLIC)
-				  ? ACCESS_PUBLIC : ACCESS_PRIVATE,
-				  sym->name, NULL))
-	    return MATCH_ERROR;
+	      && !gfc_add_access (&dt_sym->attr, access, sym->name, NULL))
+	    goto done;
 
 	  break;
 
@@ -8838,17 +8833,14 @@ access_attr_decl (gfc_statement st)
 	    {
 	      gfc_intrinsic_op other_op;
 
-	      gfc_current_ns->operator_access[op] =
-		(st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
+	      gfc_current_ns->operator_access[op] = access;
 
 	      /* Handle the case if there is another op with the same
 		 function, for INTRINSIC_EQ vs. INTRINSIC_EQ_OS and so on.  */
 	      other_op = gfc_equivalent_op (op);
 
 	      if (other_op != INTRINSIC_NONE)
-		gfc_current_ns->operator_access[other_op] =
-		  (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
-
+		gfc_current_ns->operator_access[other_op] = access;
 	    }
 	  else
 	    {
@@ -8864,8 +8856,7 @@ access_attr_decl (gfc_statement st)
 
 	  if (uop->access == ACCESS_UNKNOWN)
 	    {
-	      uop->access = (st == ST_PUBLIC)
-			  ? ACCESS_PUBLIC : ACCESS_PRIVATE;
+	      uop->access = access;
 	    }
 	  else
 	    {
@@ -8898,7 +8889,14 @@ gfc_match_protected (void)
 {
   gfc_symbol *sym;
   match m;
+  char c;
 
+  /* PROTECTED has already been seen, but must be followed by whitespace
+     or ::.  */
+  c = gfc_peek_ascii_char ();
+  if (!gfc_is_whitespace (c) && c != ':')
+    return MATCH_NO;
+
   if (!gfc_current_ns->proc_name
       || gfc_current_ns->proc_name->attr.flavor != FL_MODULE)
     {
@@ -8908,14 +8906,12 @@ gfc_match_protected (void)
 
     }
 
+  gfc_match (" ::");
+
   if (!gfc_notify_std (GFC_STD_F2003, "PROTECTED statement at %C"))
     return MATCH_ERROR;
 
-  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
-    {
-      return MATCH_ERROR;
-    }
-
+  /* PROTECTED has an entity-list.  */
   if (gfc_match_eos () == MATCH_YES)
     goto syntax;
 
@@ -8958,41 +8954,48 @@ syntax:
 match
 gfc_match_private (gfc_statement *st)
 {
+  gfc_state_data *prev;
+  char c;
 
   if (gfc_match ("private") != MATCH_YES)
     return MATCH_NO;
 
+  /* Try matching PRIVATE without an access-list.  */
+  if (gfc_match_eos () == MATCH_YES)
+    {
+      prev = gfc_state_stack->previous;
+      if (gfc_current_state () != COMP_MODULE
+	  && !(gfc_current_state () == COMP_DERIVED
+		&& prev && prev->state == COMP_MODULE)
+	  && !(gfc_current_state () == COMP_DERIVED_CONTAINS
+		&& prev->previous && prev->previous->state == COMP_MODULE))
+	{
+	  gfc_error ("PRIVATE statement at %C is only allowed in the "
+		     "specification part of a module");
+	  return MATCH_ERROR;
+	}
+
+      *st = ST_PRIVATE;
+      return MATCH_YES;
+    }
+
+  /* At this point, PRIVATE must be followed by whitespace or ::.  */
+  c = gfc_peek_ascii_char ();
+  if (!gfc_is_whitespace (c) && c != ':')
+    return MATCH_NO;
+
+  prev = gfc_state_stack->previous;
   if (gfc_current_state () != COMP_MODULE
       && !(gfc_current_state () == COMP_DERIVED
-	   && gfc_state_stack->previous
-	   && gfc_state_stack->previous->state == COMP_MODULE)
+	   && prev && prev->state == COMP_MODULE)
       && !(gfc_current_state () == COMP_DERIVED_CONTAINS
-	   && gfc_state_stack->previous && gfc_state_stack->previous->previous
-	   && gfc_state_stack->previous->previous->state == COMP_MODULE))
+	   && prev->previous && prev->previous->state == COMP_MODULE))
     {
       gfc_error ("PRIVATE statement at %C is only allowed in the "
 		 "specification part of a module");
       return MATCH_ERROR;
     }
 
-  if (gfc_current_state () == COMP_DERIVED)
-    {
-      if (gfc_match_eos () == MATCH_YES)
-	{
-	  *st = ST_PRIVATE;
-	  return MATCH_YES;
-	}
-
-      gfc_syntax_error (ST_PRIVATE);
-      return MATCH_ERROR;
-    }
-
-  if (gfc_match_eos () == MATCH_YES)
-    {
-      *st = ST_PRIVATE;
-      return MATCH_YES;
-    }
-
   *st = ST_ATTR_DECL;
   return access_attr_decl (ST_PRIVATE);
 }
@@ -9001,21 +9004,35 @@ gfc_match_private (gfc_statement *st)
 match
 gfc_match_public (gfc_statement *st)
 {
+  char c;
 
   if (gfc_match ("public") != MATCH_YES)
     return MATCH_NO;
 
+  /* Try matching PUBLIC without an access-list.  */
+  if (gfc_match_eos () == MATCH_YES)
+    {
+      if (gfc_current_state () != COMP_MODULE)
+	{
+	  gfc_error ("PUBLIC statement at %C is only allowed in the "
+		     "specification part of a module");
+	  return MATCH_ERROR;
+	}
+
+      *st = ST_PUBLIC;
+      return MATCH_YES;
+    }
+
+  /* At this point, PUBLIC must be followed by whitespace or ::.  */
+  c = gfc_peek_ascii_char ();
+  if (!gfc_is_whitespace (c) && c != ':')
+    return MATCH_NO;
+
   if (gfc_current_state () != COMP_MODULE)
     {
       gfc_error ("PUBLIC statement at %C is only allowed in the "
 		 "specification part of a module");
       return MATCH_ERROR;
-    }
-
-  if (gfc_match_eos () == MATCH_YES)
-    {
-      *st = ST_PUBLIC;
-      return MATCH_YES;
     }
 
   *st = ST_ATTR_DECL;
Index: gcc/testsuite/gfortran.dg/pr90988_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr90988_1.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/pr90988_1.f90	(working copy)
@@ -0,0 +1,14 @@
+! { dg-do compile }
+module mymod
+  type :: mytyp
+    integer :: i
+  end type mytyp
+contains
+  subroutine mysub
+    implicit none
+    type(mytyp) :: a
+    integer :: publici,publicj
+    publici = a%i
+    publicj = a%j       ! { dg-error "is not a member" }
+  end subroutine mysub
+end module mymod
Index: gcc/testsuite/gfortran.dg/pr90988_2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr90988_2.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/pr90988_2.f90	(working copy)
@@ -0,0 +1,14 @@
+! { dg-do compile }
+module mymod
+  type :: mytyp
+    integer :: i
+  end type mytyp
+contains
+  subroutine mysub
+    implicit none
+    type(mytyp) :: a
+    integer :: privatei,privatej
+    privatei = a%i
+    privatej = a%j       ! { dg-error "is not a member" }
+  end subroutine mysub
+end module mymod
Index: gcc/testsuite/gfortran.dg/pr90988_3.f90
===================================================================
--- gcc/testsuite/gfortran.dg/pr90988_3.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/pr90988_3.f90	(working copy)
@@ -0,0 +1,14 @@
+! { dg-do compile }
+module mymod
+  type :: mytyp
+    integer :: i
+  end type mytyp
+contains
+  subroutine mysub
+    implicit none
+    type(mytyp) :: a
+    integer :: protectedi,protectedj
+    protectedi = a%i
+    protectedj = a%j       ! { dg-error "is not a member" }
+  end subroutine mysub
+end module mymod

Reply via email to