C++ PATCH: Fix PRs 16518, 16337

Mark Mitchell mark@codesourcery.com
Wed Jul 14 02:06:00 GMT 2004


This patch fixes PRs 16518 and 16337, which are both regressions from
my recent decl-specifier changes.

I don't know how to do a fully portable test case for 16337.  Any
suggestions?

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-07-13  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16518
	PR c++/16337
	* decl.c (grokvardecl): Make declspecs parameter const.
	(grokdeclarator): Likewise.  Adjust accordingly.
	* decl.h (grokdeclarator): Adjust declaration.
	* parser.c (cp_parser_init_declarator): Do not clear
	decl_specifiers->attributes.

2004-07-13  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16518
	* g++.dg/parse/mutable1.C: New test.
	
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1247
diff -c -5 -p -r1.1247 decl.c
*** cp/decl.c	13 Jul 2004 16:22:04 -0000	1.1247
--- cp/decl.c	13 Jul 2004 21:08:53 -0000
*************** static int unary_op_p (enum tree_code);
*** 62,72 ****
  static void push_local_name (tree);
  static tree grok_reference_init (tree, tree, tree, tree *);
  static tree grokfndecl (tree, tree, tree, tree, tree, int,
  			enum overload_flags, cp_cv_quals,
  			tree, int, int, int, int, int, int, tree);
! static tree grokvardecl (tree, tree, cp_decl_specifier_seq *, int, int, tree);
  static void record_unknown_type (tree, const char *);
  static tree builtin_function_1 (const char *, tree, tree, int,
                                  enum built_in_class, const char *,
  				tree);
  static tree build_library_fn_1 (tree, enum tree_code, tree);
--- 62,73 ----
  static void push_local_name (tree);
  static tree grok_reference_init (tree, tree, tree, tree *);
  static tree grokfndecl (tree, tree, tree, tree, tree, int,
  			enum overload_flags, cp_cv_quals,
  			tree, int, int, int, int, int, int, tree);
! static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *, 
! 			 int, int, tree);
  static void record_unknown_type (tree, const char *);
  static tree builtin_function_1 (const char *, tree, tree, int,
                                  enum built_in_class, const char *,
  				tree);
  static tree build_library_fn_1 (tree, enum tree_code, tree);
*************** grokfndecl (tree ctype, 
*** 5706,5716 ****
     the innermost enclosings scope.  */
  
  static tree
  grokvardecl (tree type,
               tree name,
! 	     cp_decl_specifier_seq *declspecs,
               int initialized,
               int constp,
               tree scope)
  {
    tree decl;
--- 5707,5717 ----
     the innermost enclosings scope.  */
  
  static tree
  grokvardecl (tree type,
               tree name,
! 	     const cp_decl_specifier_seq *declspecs,
               int initialized,
               int constp,
               tree scope)
  {
    tree decl;
*************** check_special_function_return_type (spec
*** 6244,6254 ****
     when grokdeclarator is called for `S::f', the CURRENT_CLASS_TYPE
     should not be `S'.  */
  
  tree
  grokdeclarator (const cp_declarator *declarator,
! 		cp_decl_specifier_seq *declspecs,
                  enum decl_context decl_context,
                  int initialized,
                  tree* attrlist)
  {
    tree type = NULL_TREE;
--- 6245,6255 ----
     when grokdeclarator is called for `S::f', the CURRENT_CLASS_TYPE
     should not be `S'.  */
  
  tree
  grokdeclarator (const cp_declarator *declarator,
! 		const cp_decl_specifier_seq *declspecs,
                  enum decl_context decl_context,
                  int initialized,
                  tree* attrlist)
  {
    tree type = NULL_TREE;
*************** grokdeclarator (const cp_declarator *dec
*** 6297,6306 ****
--- 6298,6315 ----
       located.  If an unqualified name is used to declare the entity,
       this value will be NULL_TREE, even if the entity is located at
       namespace scope.  */ 
    tree in_namespace = NULL_TREE;
    cp_decl_spec ds;
+   cp_storage_class storage_class;
+   bool unsigned_p, signed_p, short_p, long_p, thread_p;
+ 
+   signed_p = declspecs->specs[(int)ds_signed];
+   unsigned_p = declspecs->specs[(int)ds_unsigned];
+   short_p = declspecs->specs[(int)ds_short];
+   long_p = declspecs->specs[(int)ds_long];
+   thread_p = declspecs->specs[(int)ds_thread];
  
    if (decl_context == FUNCDEF)
      funcdef_flag = 1, decl_context = NORMAL;
    else if (decl_context == MEMFUNCDEF)
      funcdef_flag = -1, decl_context = FIELD;
*************** grokdeclarator (const cp_declarator *dec
*** 6505,6519 ****
        typedef_decl = type;
        type = TREE_TYPE (typedef_decl);
      }
    /* No type at all: default to `int', and set DEFAULTED_INT
       because it was not a user-defined typedef.  */
!   if (type == NULL_TREE
!       && (declspecs->specs[(int)ds_signed]
! 	  || declspecs->specs[(int)ds_unsigned]
! 	  || declspecs->specs[(int)ds_long]
! 	  || declspecs->specs[(int)ds_short]))
      {
        /* These imply 'int'.  */
        type = integer_type_node;
        defaulted_int = 1;
      }
--- 6514,6524 ----
        typedef_decl = type;
        type = TREE_TYPE (typedef_decl);
      }
    /* No type at all: default to `int', and set DEFAULTED_INT
       because it was not a user-defined typedef.  */
!   if (type == NULL_TREE && (signed_p || unsigned_p || long_p || short_p))
      {
        /* These imply 'int'.  */
        type = integer_type_node;
        defaulted_int = 1;
      }
*************** grokdeclarator (const cp_declarator *dec
*** 6602,6645 ****
  
    /* Now process the modifiers that were specified
       and check for invalid combinations.  */
  
    /* Long double is a special combination.  */
!   if (declspecs->specs[(int)ds_long]
!       && TYPE_MAIN_VARIANT (type) == double_type_node)
      {
!       declspecs->specs[(int)ds_long] = 0;
        type = build_qualified_type (long_double_type_node,
  				   cp_type_quals (type));
      }
  
    /* Check all other uses of type modifiers.  */
  
!   if (declspecs->specs[(int)ds_unsigned]
!       || declspecs->specs[(int)ds_signed]
!       || declspecs->specs[(int)ds_long]
!       || declspecs->specs[(int)ds_short])
      {
        int ok = 0;
  
        if (TREE_CODE (type) == REAL_TYPE)
  	error ("short, signed or unsigned invalid for `%s'", name);
        else if (TREE_CODE (type) != INTEGER_TYPE)
  	error ("long, short, signed or unsigned invalid for `%s'", name);
!       else if (declspecs->specs[(int)ds_long]
! 	       && declspecs->specs[(int)ds_short])
  	error ("long and short specified together for `%s'", name);
!       else if ((declspecs->specs[(int)ds_long]
! 		|| declspecs->specs[(int)ds_short])
! 	       && explicit_char)
  	error ("long or short specified with char for `%s'", name);
!       else if ((declspecs->specs[(int)ds_long]
! 		|| declspecs->specs[(int)ds_short])
! 	       && TREE_CODE (type) == REAL_TYPE)
  	error ("long or short specified with floating type for `%s'", name);
!       else if (declspecs->specs[(int)ds_signed]
! 	       && declspecs->specs[(int)ds_unsigned])
  	error ("signed and unsigned given together for `%s'", name);
        else
  	{
  	  ok = 1;
  	  if (!explicit_int && !defaulted_int && !explicit_char && pedantic)
--- 6607,6640 ----
  
    /* Now process the modifiers that were specified
       and check for invalid combinations.  */
  
    /* Long double is a special combination.  */
!   if (long_p && TYPE_MAIN_VARIANT (type) == double_type_node)
      {
!       long_p = false;
        type = build_qualified_type (long_double_type_node,
  				   cp_type_quals (type));
      }
  
    /* Check all other uses of type modifiers.  */
  
!   if (unsigned_p || signed_p || long_p || short_p)
      {
        int ok = 0;
  
        if (TREE_CODE (type) == REAL_TYPE)
  	error ("short, signed or unsigned invalid for `%s'", name);
        else if (TREE_CODE (type) != INTEGER_TYPE)
  	error ("long, short, signed or unsigned invalid for `%s'", name);
!       else if (long_p && short_p)
  	error ("long and short specified together for `%s'", name);
!       else if ((long_p || short_p) && explicit_char)
  	error ("long or short specified with char for `%s'", name);
!       else if ((long_p|| short_p) && TREE_CODE (type) == REAL_TYPE)
  	error ("long or short specified with floating type for `%s'", name);
!       else if (signed_p && unsigned_p)
  	error ("signed and unsigned given together for `%s'", name);
        else
  	{
  	  ok = 1;
  	  if (!explicit_int && !defaulted_int && !explicit_char && pedantic)
*************** grokdeclarator (const cp_declarator *dec
*** 6652,6689 ****
  	}
  
        /* Discard the type modifiers if they are invalid.  */
        if (! ok)
  	{
! 	  declspecs->specs[(int)ds_unsigned] = 0;
! 	  declspecs->specs[(int)ds_signed] = 0;
! 	  declspecs->specs[(int)ds_long] = 0;
! 	  declspecs->specs[(int)ds_short] = 0;
  	  longlong = 0;
  	}
      }
  
-   if (declspecs->specs[(int)ds_complex]
-       && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
-     {
-       error ("complex invalid for `%s'", name);
-       declspecs->specs[(int)ds_complex] = 0;
-     }
- 
    /* Decide whether an integer type is signed or not.
       Optionally treat bitfields as signed by default.  */
!   if (declspecs->specs[(int)ds_unsigned]
        /* [class.bit]
  
  	 It is implementation-defined whether a plain (neither
  	 explicitly signed or unsigned) char, short, int, or long
  	 bit-field is signed or unsigned.
  
  	 Naturally, we extend this to long long as well.  Note that
  	 this does not include wchar_t.  */
        || (bitfield && !flag_signed_bitfields
! 	  && !declspecs->specs[(int)ds_signed]
  	  /* A typedef for plain `int' without `signed' can be
  	     controlled just like plain `int', but a typedef for
  	     `signed int' cannot be so controlled.  */
  	  && !(typedef_decl
  	       && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))
--- 6647,6677 ----
  	}
  
        /* Discard the type modifiers if they are invalid.  */
        if (! ok)
  	{
! 	  unsigned_p = false;
! 	  signed_p = false;
! 	  long_p = false;
! 	  short_p = false;
  	  longlong = 0;
  	}
      }
  
    /* Decide whether an integer type is signed or not.
       Optionally treat bitfields as signed by default.  */
!   if (unsigned_p
        /* [class.bit]
  
  	 It is implementation-defined whether a plain (neither
  	 explicitly signed or unsigned) char, short, int, or long
  	 bit-field is signed or unsigned.
  
  	 Naturally, we extend this to long long as well.  Note that
  	 this does not include wchar_t.  */
        || (bitfield && !flag_signed_bitfields
! 	  && !signed_p
  	  /* A typedef for plain `int' without `signed' can be
  	     controlled just like plain `int', but a typedef for
  	     `signed int' cannot be so controlled.  */
  	  && !(typedef_decl
  	       && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl))
*************** grokdeclarator (const cp_declarator *dec
*** 6691,6733 ****
  	      || TREE_CODE (type) == CHAR_TYPE)
  	  && !same_type_p (TYPE_MAIN_VARIANT (type), wchar_type_node)))
      {
        if (longlong)
  	type = long_long_unsigned_type_node;
!       else if (declspecs->specs[(int)ds_long])
  	type = long_unsigned_type_node;
!       else if (declspecs->specs[(int)ds_short])
  	type = short_unsigned_type_node;
        else if (type == char_type_node)
  	type = unsigned_char_type_node;
        else if (typedef_decl)
  	type = c_common_unsigned_type (type);
        else
  	type = unsigned_type_node;
      }
!   else if (declspecs->specs[(int)ds_signed]
! 	   && type == char_type_node)
      type = signed_char_type_node;
    else if (longlong)
      type = long_long_integer_type_node;
!   else if (declspecs->specs[(int)ds_long])
      type = long_integer_type_node;
!   else if (declspecs->specs[(int)ds_short])
      type = short_integer_type_node;
  
    if (declspecs->specs[(int)ds_complex])
      {
        /* If we just have "complex", it is equivalent to
  	 "complex double", but if any modifiers at all are specified it is
  	 the complex form of TYPE.  E.g, "complex short" is
  	 "complex short int".  */
  
!       if (defaulted_int && ! longlong
! 	  && ! (declspecs->specs[(int)ds_long]
! 		|| declspecs->specs[(int)ds_short]
! 		|| declspecs->specs[(int)ds_signed]
! 		|| declspecs->specs[(int)ds_unsigned]))
  	type = complex_double_type_node;
        else if (type == integer_type_node)
  	type = complex_integer_type_node;
        else if (type == float_type_node)
  	type = complex_float_type_node;
--- 6679,6719 ----
  	      || TREE_CODE (type) == CHAR_TYPE)
  	  && !same_type_p (TYPE_MAIN_VARIANT (type), wchar_type_node)))
      {
        if (longlong)
  	type = long_long_unsigned_type_node;
!       else if (long_p)
  	type = long_unsigned_type_node;
!       else if (short_p)
  	type = short_unsigned_type_node;
        else if (type == char_type_node)
  	type = unsigned_char_type_node;
        else if (typedef_decl)
  	type = c_common_unsigned_type (type);
        else
  	type = unsigned_type_node;
      }
!   else if (signed_p && type == char_type_node)
      type = signed_char_type_node;
    else if (longlong)
      type = long_long_integer_type_node;
!   else if (long_p)
      type = long_integer_type_node;
!   else if (short_p)
      type = short_integer_type_node;
  
    if (declspecs->specs[(int)ds_complex])
      {
+       if (TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
+ 	error ("complex invalid for `%s'", name);
        /* If we just have "complex", it is equivalent to
  	 "complex double", but if any modifiers at all are specified it is
  	 the complex form of TYPE.  E.g, "complex short" is
  	 "complex short int".  */
  
!       else if (defaulted_int && ! longlong
! 	       && ! (long_p || short_p || signed_p || unsigned_p))
  	type = complex_double_type_node;
        else if (type == integer_type_node)
  	type = complex_integer_type_node;
        else if (type == float_type_node)
  	type = complex_float_type_node;
*************** grokdeclarator (const cp_declarator *dec
*** 6760,6770 ****
    staticp = 0;
    inlinep = !! declspecs->specs[(int)ds_inline];
    virtualp = !! declspecs->specs[(int)ds_virtual];
    explicitp = !! declspecs->specs[(int)ds_explicit];
  
!   if (declspecs->storage_class == sc_static)
      staticp = 1 + (decl_context == FIELD);
  
    if (virtualp && staticp == 2)
      {
        error ("member `%D' cannot be declared both virtual and static",
--- 6746,6757 ----
    staticp = 0;
    inlinep = !! declspecs->specs[(int)ds_inline];
    virtualp = !! declspecs->specs[(int)ds_virtual];
    explicitp = !! declspecs->specs[(int)ds_explicit];
  
!   storage_class = declspecs->storage_class;
!   if (storage_class == sc_static)
      staticp = 1 + (decl_context == FIELD);
  
    if (virtualp && staticp == 2)
      {
        error ("member `%D' cannot be declared both virtual and static",
*************** grokdeclarator (const cp_declarator *dec
*** 6782,6794 ****
    /* Issue errors about use of storage classes for parameters.  */
    if (decl_context == PARM)
      {
        if (declspecs->specs[(int)ds_typedef])
  	error ("typedef declaration invalid in parameter declaration");
!       else if (declspecs->storage_class == sc_static
! 	       || declspecs->storage_class == sc_extern
! 	       || declspecs->specs[(int)ds_thread])
  	error ("storage class specifiers invalid in parameter declarations");
      }
  
    /* Give error if `virtual' is used outside of class declaration.  */
    if (virtualp
--- 6769,6781 ----
    /* Issue errors about use of storage classes for parameters.  */
    if (decl_context == PARM)
      {
        if (declspecs->specs[(int)ds_typedef])
  	error ("typedef declaration invalid in parameter declaration");
!       else if (storage_class == sc_static
! 	       || storage_class == sc_extern
! 	       || thread_p)
  	error ("storage class specifiers invalid in parameter declarations");
      }
  
    /* Give error if `virtual' is used outside of class declaration.  */
    if (virtualp
*************** grokdeclarator (const cp_declarator *dec
*** 6806,6838 ****
  
    /* Warn about storage classes that are invalid for certain
       kinds of declarations (parameters, typenames, etc.).  */
    if (declspecs->multiple_storage_classes_p)
      error ("multiple storage classes in declaration of `%s'", name);
!   else if (declspecs->specs[(int)ds_thread]
! 	   && ((declspecs->storage_class 
! 		&& declspecs->storage_class != sc_extern
! 		&& declspecs->storage_class != sc_static)
  	       || declspecs->specs[(int)ds_typedef]))
      {
        error ("multiple storage classes in declaration of `%s'", name);
!       declspecs->specs[(int)ds_thread] = 0;
      }
    else if (decl_context != NORMAL 
! 	   && ((declspecs->storage_class != sc_none
! 		&& declspecs->storage_class != sc_mutable)
! 	       || declspecs->specs[(int)ds_thread]))
      {
        if ((decl_context == PARM || decl_context == CATCHPARM)
! 	  && (declspecs->storage_class == sc_register
! 	      || declspecs->storage_class == sc_auto))
  	;
        else if (declspecs->specs[(int)ds_typedef])
  	;
        else if (decl_context == FIELD
  	       /* C++ allows static class elements.  */
! 	       && declspecs->storage_class == sc_static)
  	/* C++ also allows inlines and signed and unsigned elements,
  	   but in those cases we don't come in here.  */
  	;
        else
  	{
--- 6793,6825 ----
  
    /* Warn about storage classes that are invalid for certain
       kinds of declarations (parameters, typenames, etc.).  */
    if (declspecs->multiple_storage_classes_p)
      error ("multiple storage classes in declaration of `%s'", name);
!   else if (thread_p
! 	   && ((storage_class 
! 		&& storage_class != sc_extern
! 		&& storage_class != sc_static)
  	       || declspecs->specs[(int)ds_typedef]))
      {
        error ("multiple storage classes in declaration of `%s'", name);
!       thread_p = false;
      }
    else if (decl_context != NORMAL 
! 	   && ((storage_class != sc_none
! 		&& storage_class != sc_mutable)
! 	       || thread_p))
      {
        if ((decl_context == PARM || decl_context == CATCHPARM)
! 	  && (storage_class == sc_register
! 	      || storage_class == sc_auto))
  	;
        else if (declspecs->specs[(int)ds_typedef])
  	;
        else if (decl_context == FIELD
  	       /* C++ allows static class elements.  */
! 	       && storage_class == sc_static)
  	/* C++ also allows inlines and signed and unsigned elements,
  	   but in those cases we don't come in here.  */
  	;
        else
  	{
*************** grokdeclarator (const cp_declarator *dec
*** 6866,6883 ****
  	      if (decl_context == PARM || decl_context == CATCHPARM)
  		error ("storage class specified for parameter `%s'", name);
  	      else
  		error ("storage class specified for typename");
  	    }
! 	  if (declspecs->storage_class == sc_register
! 	      || declspecs->storage_class == sc_auto
! 	      || declspecs->storage_class == sc_extern
! 	      || declspecs->specs[(int)ds_thread])
! 	    declspecs->storage_class = sc_none;
  	}
      }
!   else if (declspecs->storage_class == sc_extern && initialized 
  	   && !funcdef_flag)
      {
        if (toplevel_bindings_p ())
  	{
  	  /* It's common practice (and completely valid) to have a const
--- 6853,6870 ----
  	      if (decl_context == PARM || decl_context == CATCHPARM)
  		error ("storage class specified for parameter `%s'", name);
  	      else
  		error ("storage class specified for typename");
  	    }
! 	  if (storage_class == sc_register
! 	      || storage_class == sc_auto
! 	      || storage_class == sc_extern
! 	      || thread_p)
! 	    storage_class = sc_none;
  	}
      }
!   else if (storage_class == sc_extern && initialized 
  	   && !funcdef_flag)
      {
        if (toplevel_bindings_p ())
  	{
  	  /* It's common practice (and completely valid) to have a const
*************** grokdeclarator (const cp_declarator *dec
*** 6886,6913 ****
  	    warning ("`%s' initialized and declared `extern'", name);
  	}
        else
  	error ("`%s' has both `extern' and initializer", name);
      }
!   else if (declspecs->storage_class == sc_extern && funcdef_flag
  	   && ! toplevel_bindings_p ())
      error ("nested function `%s' declared `extern'", name);
    else if (toplevel_bindings_p ())
      {
!       if (declspecs->storage_class == sc_auto)
  	error ("top-level declaration of `%s' specifies `auto'", name);
      }
!   else if (declspecs->specs[(int)ds_thread]
! 	   && declspecs->storage_class != sc_extern
! 	   && declspecs->storage_class != sc_static)
      {
        error ("function-scope `%s' implicitly auto and declared `__thread'",
  	     name);
!       declspecs->specs[(int)ds_thread] = 0;
      }
  
!   if (declspecs->storage_class && friendp)
      error ("storage class specifiers invalid in friend function declarations");
  
    if (!id_declarator)
      unqualified_id = NULL_TREE;
    else
--- 6873,6900 ----
  	    warning ("`%s' initialized and declared `extern'", name);
  	}
        else
  	error ("`%s' has both `extern' and initializer", name);
      }
!   else if (storage_class == sc_extern && funcdef_flag
  	   && ! toplevel_bindings_p ())
      error ("nested function `%s' declared `extern'", name);
    else if (toplevel_bindings_p ())
      {
!       if (storage_class == sc_auto)
  	error ("top-level declaration of `%s' specifies `auto'", name);
      }
!   else if (thread_p
! 	   && storage_class != sc_extern
! 	   && storage_class != sc_static)
      {
        error ("function-scope `%s' implicitly auto and declared `__thread'",
  	     name);
!       thread_p = false;
      }
  
!   if (storage_class && friendp)
      error ("storage class specifiers invalid in friend function declarations");
  
    if (!id_declarator)
      unqualified_id = NULL_TREE;
    else
*************** grokdeclarator (const cp_declarator *dec
*** 7332,7368 ****
           declarations of constructors within a class definition.  */
        error ("only declarations of constructors can be `explicit'");
        explicitp = 0;
      }
  
!   if (declspecs->storage_class == sc_mutable)
      {
        if (decl_context != FIELD || friendp)
          {
  	  error ("non-member `%s' cannot be declared `mutable'", name);
! 	  declspecs->storage_class = sc_none;
          }
        else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef])
  	{
  	  error ("non-object member `%s' cannot be declared `mutable'", name);
! 	  declspecs->storage_class = sc_none;
  	}
        else if (TREE_CODE (type) == FUNCTION_TYPE
                 || TREE_CODE (type) == METHOD_TYPE)
          {
  	  error ("function `%s' cannot be declared `mutable'", name);
! 	  declspecs->storage_class = sc_none;
          }
        else if (staticp)
  	{
  	  error ("static `%s' cannot be declared `mutable'", name);
! 	  declspecs->storage_class = sc_none;
  	}
        else if (type_quals & TYPE_QUAL_CONST)
  	{
  	  error ("const `%s' cannot be declared `mutable'", name);
! 	  declspecs->storage_class = sc_none;
  	}
      }
  
    /* If this is declaring a typedef name, return a TYPE_DECL.  */
    if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME)
--- 7319,7355 ----
           declarations of constructors within a class definition.  */
        error ("only declarations of constructors can be `explicit'");
        explicitp = 0;
      }
  
!   if (storage_class == sc_mutable)
      {
        if (decl_context != FIELD || friendp)
          {
  	  error ("non-member `%s' cannot be declared `mutable'", name);
! 	  storage_class = sc_none;
          }
        else if (decl_context == TYPENAME || declspecs->specs[(int)ds_typedef])
  	{
  	  error ("non-object member `%s' cannot be declared `mutable'", name);
! 	  storage_class = sc_none;
  	}
        else if (TREE_CODE (type) == FUNCTION_TYPE
                 || TREE_CODE (type) == METHOD_TYPE)
          {
  	  error ("function `%s' cannot be declared `mutable'", name);
! 	  storage_class = sc_none;
          }
        else if (staticp)
  	{
  	  error ("static `%s' cannot be declared `mutable'", name);
! 	  storage_class = sc_none;
  	}
        else if (type_quals & TYPE_QUAL_CONST)
  	{
  	  error ("const `%s' cannot be declared `mutable'", name);
! 	  storage_class = sc_none;
  	}
      }
  
    /* If this is declaring a typedef name, return a TYPE_DECL.  */
    if (declspecs->specs[(int)ds_typedef] && decl_context != TYPENAME)
*************** grokdeclarator (const cp_declarator *dec
*** 7438,7448 ****
  	    }
  	  if (ctype != NULL_TREE)
  	    grok_method_quals (ctype, decl, quals);
  	}
  
!       if (declspecs->specs[(int)ds_signed]
  	  || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
  	C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
  
        bad_specifiers (decl, "type", virtualp, quals != TYPE_UNQUALIFIED, 
  		      inlinep, friendp, raises != NULL_TREE);
--- 7425,7435 ----
  	    }
  	  if (ctype != NULL_TREE)
  	    grok_method_quals (ctype, decl, quals);
  	}
  
!       if (signed_p
  	  || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
  	C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
  
        bad_specifiers (decl, "type", virtualp, quals != TYPE_UNQUALIFIED, 
  		      inlinep, friendp, raises != NULL_TREE);
*************** grokdeclarator (const cp_declarator *dec
*** 7855,7868 ****
  	      }
  	    else
  	      {
  		decl = build_decl (FIELD_DECL, unqualified_id, type);
  		DECL_NONADDRESSABLE_P (decl) = bitfield;
! 		if (declspecs->storage_class == sc_mutable)
  		  {
  		    DECL_MUTABLE_P (decl) = 1;
! 		    declspecs->storage_class = sc_none;
  		  }
  	      }
  
  	    bad_specifiers (decl, "field", virtualp, quals != TYPE_UNQUALIFIED,
  			    inlinep, friendp, raises != NULL_TREE);
--- 7842,7855 ----
  	      }
  	    else
  	      {
  		decl = build_decl (FIELD_DECL, unqualified_id, type);
  		DECL_NONADDRESSABLE_P (decl) = bitfield;
! 		if (storage_class == sc_mutable)
  		  {
  		    DECL_MUTABLE_P (decl) = 1;
! 		    storage_class = sc_none;
  		  }
  	      }
  
  	    bad_specifiers (decl, "field", virtualp, quals != TYPE_UNQUALIFIED,
  			    inlinep, friendp, raises != NULL_TREE);
*************** grokdeclarator (const cp_declarator *dec
*** 7880,7905 ****
  	if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
  	  original_name = dname;
  	else
  	  original_name = unqualified_id;
  
! 	if (declspecs->storage_class == sc_auto)
  	  error ("storage class `auto' invalid for function `%s'", name);
! 	else if (declspecs->storage_class == sc_register)
  	  error ("storage class `register' invalid for function `%s'", name);
! 	else if (declspecs->specs[(int)ds_thread])
  	  error ("storage class `__thread' invalid for function `%s'", name);
  
  	/* Function declaration not at top level.
  	   Storage classes other than `extern' are not allowed
  	   and `extern' makes no difference.  */
  	if (! toplevel_bindings_p ()
! 	    && (declspecs->storage_class == sc_static
  		|| declspecs->specs[(int)ds_inline])
  	    && pedantic)
  	  {
! 	    if (declspecs->storage_class == sc_static)
  	      pedwarn ("`static' specified invalid for function `%s' declared out of global scope", name);
  	    else
  	      pedwarn ("`inline' specifier invalid for function `%s' declared out of global scope", name);
  	  }
  
--- 7867,7892 ----
  	if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
  	  original_name = dname;
  	else
  	  original_name = unqualified_id;
  
! 	if (storage_class == sc_auto)
  	  error ("storage class `auto' invalid for function `%s'", name);
! 	else if (storage_class == sc_register)
  	  error ("storage class `register' invalid for function `%s'", name);
! 	else if (thread_p)
  	  error ("storage class `__thread' invalid for function `%s'", name);
  
  	/* Function declaration not at top level.
  	   Storage classes other than `extern' are not allowed
  	   and `extern' makes no difference.  */
  	if (! toplevel_bindings_p ()
! 	    && (storage_class == sc_static
  		|| declspecs->specs[(int)ds_inline])
  	    && pedantic)
  	  {
! 	    if (storage_class == sc_static)
  	      pedwarn ("`static' specified invalid for function `%s' declared out of global scope", name);
  	    else
  	      pedwarn ("`inline' specifier invalid for function `%s' declared out of global scope", name);
  	  }
  
*************** grokdeclarator (const cp_declarator *dec
*** 7917,7928 ****
  					     TREE_TYPE (type),
  					     TYPE_ARG_TYPES (type));
  
  	/* Record presence of `static'.  */
  	publicp = (ctype != NULL_TREE
! 		   || declspecs->storage_class == sc_extern
! 		   || declspecs->storage_class != sc_static);
  
  	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
  			   virtualp, flags, quals, raises,
  			   1, friendp,
  			   publicp, inlinep, funcdef_flag,
--- 7904,7915 ----
  					     TREE_TYPE (type),
  					     TYPE_ARG_TYPES (type));
  
  	/* Record presence of `static'.  */
  	publicp = (ctype != NULL_TREE
! 		   || storage_class == sc_extern
! 		   || storage_class != sc_static);
  
  	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
  			   virtualp, flags, quals, raises,
  			   1, friendp,
  			   publicp, inlinep, funcdef_flag,
*************** grokdeclarator (const cp_declarator *dec
*** 7949,7959 ****
  	      }
  
  	    if (invalid_static)
  	      {
  		staticp = 0;
! 		declspecs->storage_class = sc_none;
  	      }
  	  }
        }
      else
        {
--- 7936,7946 ----
  	      }
  
  	    if (invalid_static)
  	      {
  		staticp = 0;
! 		storage_class = sc_none;
  	      }
  	  }
        }
      else
        {
*************** grokdeclarator (const cp_declarator *dec
*** 7973,8006 ****
  	    DECL_CONTEXT (decl) = ctype;
  	    if (staticp == 1)
  	      {
                  pedwarn ("`static' may not be used when defining (as opposed to declaring) a static data member");
  	        staticp = 0;
! 		declspecs->storage_class = sc_none;
  	      }
! 	    if (declspecs->storage_class == sc_register && TREE_STATIC (decl))
  	      {
  		error ("static member `%D' declared `register'", decl);
! 		declspecs->storage_class = sc_none;
  	      }
! 	    if (declspecs->storage_class == sc_extern && pedantic)
  	      {
  	        pedwarn ("cannot explicitly declare member `%#D' to have extern linkage",
  			    decl);
! 		declspecs->storage_class = sc_none;
  	      }
  	  }
        }
  
      /* Record `register' declaration for warnings on &
         and in case doing stupid register allocation.  */
  
!     if (declspecs->storage_class == sc_register)
        DECL_REGISTER (decl) = 1;
!     else if (declspecs->storage_class == sc_extern)
        DECL_THIS_EXTERN (decl) = 1;
!     else if (declspecs->storage_class == sc_static)
        DECL_THIS_STATIC (decl) = 1;
  
      /* Record constancy and volatility.  There's no need to do this
         when processing a template; we'll do this for the instantiated
         declaration based on the type of DECL.  */
--- 7960,7993 ----
  	    DECL_CONTEXT (decl) = ctype;
  	    if (staticp == 1)
  	      {
                  pedwarn ("`static' may not be used when defining (as opposed to declaring) a static data member");
  	        staticp = 0;
! 		storage_class = sc_none;
  	      }
! 	    if (storage_class == sc_register && TREE_STATIC (decl))
  	      {
  		error ("static member `%D' declared `register'", decl);
! 		storage_class = sc_none;
  	      }
! 	    if (storage_class == sc_extern && pedantic)
  	      {
  	        pedwarn ("cannot explicitly declare member `%#D' to have extern linkage",
  			    decl);
! 		storage_class = sc_none;
  	      }
  	  }
        }
  
      /* Record `register' declaration for warnings on &
         and in case doing stupid register allocation.  */
  
!     if (storage_class == sc_register)
        DECL_REGISTER (decl) = 1;
!     else if (storage_class == sc_extern)
        DECL_THIS_EXTERN (decl) = 1;
!     else if (storage_class == sc_static)
        DECL_THIS_STATIC (decl) = 1;
  
      /* Record constancy and volatility.  There's no need to do this
         when processing a template; we'll do this for the instantiated
         declaration based on the type of DECL.  */
Index: cp/decl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.h,v
retrieving revision 1.15
diff -c -5 -p -r1.15 decl.h
*** cp/decl.h	24 Jun 2004 06:48:43 -0000	1.15
--- cp/decl.h	13 Jul 2004 21:08:53 -0000
*************** enum decl_context
*** 30,40 ****
    MEMFUNCDEF			/* Member function definition */
  };
  
  /* We need this in here to get the decl_context definition.  */
  extern tree grokdeclarator (const cp_declarator *, 
! 			    cp_decl_specifier_seq *, 
  			    enum decl_context, int, tree*);
  
  #ifdef DEBUG_CP_BINDING_LEVELS
  /* Purely for debugging purposes.  */
  extern int debug_bindings_indentation;
--- 30,40 ----
    MEMFUNCDEF			/* Member function definition */
  };
  
  /* We need this in here to get the decl_context definition.  */
  extern tree grokdeclarator (const cp_declarator *, 
! 			    const cp_decl_specifier_seq *, 
  			    enum decl_context, int, tree*);
  
  #ifdef DEBUG_CP_BINDING_LEVELS
  /* Purely for debugging purposes.  */
  extern int debug_bindings_indentation;
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.227
diff -c -5 -p -r1.227 parser.c
*** cp/parser.c	12 Jul 2004 19:10:03 -0000	1.227
--- cp/parser.c	13 Jul 2004 21:08:53 -0000
*************** cp_parser_init_declarator (cp_parser* pa
*** 10475,10485 ****
    bool pop_p = false;
  
    /* Gather the attributes that were provided with the
       decl-specifiers.  */
    prefix_attributes = decl_specifiers->attributes;
-   decl_specifiers->attributes = NULL_TREE;
  
    /* Assume that this is not the declarator for a function
       definition.  */
    if (function_definition_p)
      *function_definition_p = false;
--- 10475,10484 ----
Index: testsuite/g++.dg/parse/mutable1.C
===================================================================
RCS file: testsuite/g++.dg/parse/mutable1.C
diff -N testsuite/g++.dg/parse/mutable1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/mutable1.C	13 Jul 2004 21:08:53 -0000
***************
*** 0 ****
--- 1,7 ----
+ // PR c++/16518
+ 
+ struct foo { 
+   void bar() const { m1=1; m2=1;} 
+   mutable int m1,m2; 
+ }; 
+  



More information about the Gcc-patches mailing list