public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/88548, this accepted in static member functions
@ 2018-12-23 10:30 Marek Polacek
  2019-01-04 14:44 ` Marek Polacek
  2019-01-08  4:08 ` Jason Merrill
  0 siblings, 2 replies; 3+ messages in thread
From: Marek Polacek @ 2018-12-23 10:30 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

I noticed that we weren't diagnosing using 'this' in noexcept-specifiers
of static member functions, and Jakub pointed out that this is also true
for trailing-return-type.  cp_parser has local_variables_forbidden_p to
detect using local vars and 'this' in certain contexts, so let's use that.

...except that I found out that I need to be able to distinguish between
forbidding just local vars and/or this, so I've changed its type to char.
For instance, you can't use 'this' in a static member function declaration,
but you can use a local var because noexcept/decltype is an unevaluated
context.

I also noticed that we weren't diagnosing 'this' in a friend declaration,
which is also forbidden.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-12-22  Marek Polacek  <polacek@redhat.com>

	PR c++/88548 - this accepted in static member functions.
	* parser.c (cp_debug_parser): Adjust printing of
	local_variables_forbidden_p.
	(cp_parser_new): Set local_variables_forbidden_p to 0 rather than false.
	(cp_parser_primary_expression): When checking
	local_variables_forbidden_p, use THIS_FORBIDDEN or
	LOCAL_VARS_FORBIDDEN.
	(cp_parser_lambda_body): Update the type of
	local_variables_forbidden_p.  Set it to 0 rather than false.
	(cp_parser_condition): Adjust call to cp_parser_declarator.
	(cp_parser_explicit_instantiation): Likewise.
	(cp_parser_init_declarator): Likewise.
	(cp_parser_declarator): New parameter.  Use it.
	(cp_parser_direct_declarator): New parameter.  Use it to set
	local_variables_forbidden_p.  Adjust call to cp_parser_declarator.
	(cp_parser_type_id_1): Adjust call to cp_parser_declarator.
	(cp_parser_parameter_declaration): Likewise.
	(cp_parser_default_argument): Update the type of
	local_variables_forbidden_p.  Set it to LOCAL_VARS_AND_THIS_FORBIDDEN
	rather than true.
	(cp_parser_member_declaration): Tell cp_parser_declarator if we saw
	'static' or 'friend'.
	(cp_parser_exception_declaration): Adjust call to cp_parser_declarator.
	(cp_parser_late_parsing_default_args): Update the type of
	local_variables_forbidden_p.  Set it to LOCAL_VARS_AND_THIS_FORBIDDEN
	rather than true.
	(cp_parser_cache_defarg): Adjust call to cp_parser_declarator.
	(cp_parser_objc_class_ivars): Likewise.
	(cp_parser_objc_struct_declaration): Likewise.
	(cp_parser_omp_for_loop_init): Likewise.
	* parser.h (cp_parser): Change the type of local_variables_forbidden_p
	to unsigned char.
	(LOCAL_VARS_FORBIDDEN, LOCAL_VARS_AND_THIS_FORBIDDEN, THIS_FORBIDDEN):
	Define.

	* g++.dg/cpp0x/this1.C: New test.

diff --git gcc/cp/parser.c gcc/cp/parser.c
index 2cd91a37031..8aab21f3d33 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -536,9 +536,12 @@ cp_debug_parser (FILE *file, cp_parser *parser)
 			      parser->allow_non_integral_constant_expression_p);
   cp_debug_print_flag (file, "Seen non-constant expression",
 			      parser->non_integral_constant_expression_p);
-  cp_debug_print_flag (file, "Local names and 'this' forbidden in "
-			      "current context",
-			      parser->local_variables_forbidden_p);
+  cp_debug_print_flag (file, "Local names forbidden in current context",
+			      (parser->local_variables_forbidden_p
+			       & LOCAL_VARS_FORBIDDEN));
+  cp_debug_print_flag (file, "'this' forbidden in current context",
+			      (parser->local_variables_forbidden_p
+			       & THIS_FORBIDDEN));
   cp_debug_print_flag (file, "In unbraced linkage specification",
 			      parser->in_unbraced_linkage_specification_p);
   cp_debug_print_flag (file, "Parsing a declarator",
@@ -2203,9 +2206,10 @@ static tree cp_parser_init_declarator
    location_t *, tree *);
 static cp_declarator *cp_parser_declarator
   (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *,
-   bool, bool);
+   bool, bool, bool);
 static cp_declarator *cp_parser_direct_declarator
-  (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool);
+  (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool,
+   bool);
 static enum tree_code cp_parser_ptr_operator
   (cp_parser *, tree *, cp_cv_quals *, tree *);
 static cp_cv_quals cp_parser_cv_qualifier_seq_opt
@@ -3951,7 +3955,7 @@ cp_parser_new (void)
   parser->non_integral_constant_expression_p = false;
 
   /* Local variable names are not forbidden.  */
-  parser->local_variables_forbidden_p = false;
+  parser->local_variables_forbidden_p = 0;
 
   /* We are not processing an `extern "C"' declaration.  */
   parser->in_unbraced_linkage_specification_p = false;
@@ -5405,7 +5409,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	  /* Recognize the `this' keyword.  */
 	case RID_THIS:
 	  cp_lexer_consume_token (parser->lexer);
-	  if (parser->local_variables_forbidden_p)
+	  if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
 	    {
 	      error_at (token->location,
 			"%<this%> may not be used in this context");
@@ -5681,14 +5685,14 @@ cp_parser_primary_expression (cp_parser *parser,
 		      template <int N> struct A {
 			int a[B<N>::i];
 		      };
-		     
+
 		   is accepted.  At template-instantiation time, we
 		   will check that B<N>::i is actually a constant.  */
 		return decl;
 	      }
 	    /* Check to see if DECL is a local variable in a context
 	       where that is forbidden.  */
-	    if (parser->local_variables_forbidden_p
+	    if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
 		&& local_variable_p (decl))
 	      {
 		error_at (id_expression.get_location (),
@@ -10902,7 +10906,8 @@ static void
 cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
 {
   bool nested = (current_function_decl != NULL_TREE);
-  bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
+  unsigned char local_variables_forbidden_p
+    = parser->local_variables_forbidden_p;
   bool in_function_body = parser->in_function_body;
 
   /* The body of a lambda-expression is not a subexpression of the enclosing
@@ -10919,7 +10924,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
   vec<tree> omp_privatization_save;
   save_omp_privatization_clauses (omp_privatization_save);
   /* Clear this in case we're in the middle of a default argument.  */
-  parser->local_variables_forbidden_p = false;
+  parser->local_variables_forbidden_p = 0;
   parser->in_function_body = true;
 
   {
@@ -11964,7 +11969,8 @@ cp_parser_condition (cp_parser* parser)
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
 					 /*member_p=*/false,
-					 /*friend_p=*/false);
+					 /*friend_p=*/false,
+					 /*static_p=*/false);
       /* Parse the attributes.  */
       attributes = cp_parser_attributes_opt (parser);
       /* Parse the asm-specification.  */
@@ -17097,7 +17103,8 @@ cp_parser_explicit_instantiation (cp_parser* parser)
 				/*ctor_dtor_or_conv_p=*/NULL,
 				/*parenthesized_p=*/NULL,
 				/*member_p=*/false,
-				/*friend_p=*/false);
+				/*friend_p=*/false,
+				/*static_p=*/false);
       if (declares_class_or_enum & 2)
 	cp_parser_check_for_definition_in_return_type (declarator,
 						       decl_specifiers.type,
@@ -20042,7 +20049,7 @@ cp_parser_init_declarator (cp_parser* parser,
     = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 			    flags, &ctor_dtor_or_conv_p,
 			    /*parenthesized_p=*/NULL,
-			    member_p, friend_p);
+			    member_p, friend_p, /*static_p=*/false);
   /* Gather up the deferred checks.  */
   stop_deferring_access_checks ();
 
@@ -20460,7 +20467,9 @@ cp_parser_init_declarator (cp_parser* parser,
 
    MEMBER_P is true iff this declarator is a member-declarator.
 
-   FRIEND_P is true iff this declarator is a friend.  */
+   FRIEND_P is true iff this declarator is a friend.
+
+   STATIC_P is true iff the keyword static was seen.  */
 
 static cp_declarator *
 cp_parser_declarator (cp_parser* parser,
@@ -20468,7 +20477,7 @@ cp_parser_declarator (cp_parser* parser,
 		      cp_parser_flags flags,
 		      int* ctor_dtor_or_conv_p,
 		      bool* parenthesized_p,
-		      bool member_p, bool friend_p)
+		      bool member_p, bool friend_p, bool static_p)
 {
   cp_declarator *declarator;
   enum tree_code code;
@@ -20510,7 +20519,7 @@ cp_parser_declarator (cp_parser* parser,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
 					 /*member_p=*/false,
-					 friend_p);
+					 friend_p, /*static_p=*/false);
 
       /* If we are parsing an abstract-declarator, we must handle the
 	 case where the dependent declarator is absent.  */
@@ -20529,7 +20538,7 @@ cp_parser_declarator (cp_parser* parser,
 						   CPP_OPEN_PAREN);
       declarator = cp_parser_direct_declarator (parser, dcl_kind,
 						flags, ctor_dtor_or_conv_p,
-						member_p, friend_p);
+						member_p, friend_p, static_p);
     }
 
   if (gnu_attributes && declarator && declarator != cp_error_declarator)
@@ -20565,7 +20574,7 @@ cp_parser_declarator (cp_parser* parser,
    of ambiguity we prefer an abstract declarator, as per
    [dcl.ambig.res].
    The parser flags FLAGS is used to control type-specifier parsing.
-   CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are
+   CTOR_DTOR_OR_CONV_P, MEMBER_P, FRIEND_P, and STATIC_P are
    as for cp_parser_declarator.  */
 
 static cp_declarator *
@@ -20573,7 +20582,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 			     cp_parser_declarator_kind dcl_kind,
 			     cp_parser_flags flags,
 			     int* ctor_dtor_or_conv_p,
-			     bool member_p, bool friend_p)
+			     bool member_p, bool friend_p, bool static_p)
 {
   cp_token *token;
   cp_declarator *declarator = NULL;
@@ -20676,6 +20685,11 @@ cp_parser_direct_declarator (cp_parser* parser,
 		  tree attrs;
 		  bool memfn = (member_p || (pushed_scope
 					     && CLASS_TYPE_P (pushed_scope)));
+		  unsigned char local_variables_forbidden_p
+		    = parser->local_variables_forbidden_p;
+		  /* 'this' is not allowed in static member functions.  */
+		  if (static_p || friend_p)
+		    parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
 
 		  is_declarator = true;
 
@@ -20723,6 +20737,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 		     return type, so are not those of the declared
 		     function.  */
 		  parser->default_arg_ok_p = false;
+
+		  /* Restore the state of local_variables_forbidden_p.  */
+		  parser->local_variables_forbidden_p
+		    = local_variables_forbidden_p;
 		}
 
 	      /* Remove the function parms from scope.  */
@@ -20753,7 +20771,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 		= cp_parser_declarator (parser, dcl_kind, flags,
 					ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
-					member_p, friend_p);
+					member_p, friend_p,
+					/*static_p=*/false);
 	      parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
 	      first = false;
 	      /* Expect a `)'.  */
@@ -21647,7 +21666,8 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
 			    CP_PARSER_FLAGS_NONE, NULL,
 			    /*parenthesized_p=*/NULL,
 			    /*member_p=*/false,
-			    /*friend_p=*/false);
+			    /*friend_p=*/false,
+			    /*static_p=*/false);
   /* Check to see if there really was a declarator.  */
   if (!cp_parser_parse_definitely (parser))
     abstract_declarator = NULL;
@@ -22232,7 +22252,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 parenthesized_p,
 					 /*member_p=*/false,
-					 /*friend_p=*/false);
+					 /*friend_p=*/false,
+					 /*static_p=*/false);
       parser->default_arg_ok_p = saved_default_arg_ok_p;
       /* After the declarator, allow more attributes.  */
       decl_specifiers.attributes
@@ -22413,7 +22434,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
 {
   tree default_argument = NULL_TREE;
   bool saved_greater_than_is_operator_p;
-  bool saved_local_variables_forbidden_p;
+  unsigned char saved_local_variables_forbidden_p;
   bool non_constant_p, is_direct_init;
 
   /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
@@ -22423,7 +22444,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
   /* Local variable names (and the `this' keyword) may not
      appear in a default argument.  */
   saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
-  parser->local_variables_forbidden_p = true;
+  parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
   /* Parse the assignment-expression.  */
   if (template_parm_p)
     push_deferring_access_checks (dk_no_deferred);
@@ -24442,6 +24463,7 @@ cp_parser_member_declaration (cp_parser* parser)
 	      cp_declarator *declarator;
 	      tree asm_specification;
 	      int ctor_dtor_or_conv_p;
+	      bool static_p = (decl_specifiers.storage_class == sc_static);
 
 	      /* Parse the declarator.  */
 	      declarator
@@ -24450,7 +24472,7 @@ cp_parser_member_declaration (cp_parser* parser)
 					&ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
 					/*member_p=*/true,
-					friend_p);
+					friend_p, static_p);
 
 	      /* If something went wrong parsing the declarator, make sure
 		 that we at least consume some tokens.  */
@@ -25331,7 +25353,8 @@ cp_parser_exception_declaration (cp_parser* parser)
 				       /*ctor_dtor_or_conv_p=*/NULL,
 				       /*parenthesized_p=*/NULL,
 				       /*member_p=*/false,
-				       /*friend_p=*/false);
+				       /*friend_p=*/false,
+				       /*static_p=*/false);
 
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
@@ -28576,7 +28599,7 @@ cp_parser_late_parsing_nsdmi (cp_parser *parser, tree field)
 static void
 cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
 {
-  bool saved_local_variables_forbidden_p;
+  unsigned char saved_local_variables_forbidden_p;
   tree parm, parmdecl;
 
   /* While we're parsing the default args, we might (due to the
@@ -28588,7 +28611,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
   /* Local variable names (and the `this' keyword) may not appear
      in a default argument.  */
   saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
-  parser->local_variables_forbidden_p = true;
+  parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
 
   push_defarg_context (fn);
 
@@ -29667,7 +29690,8 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
 					    &ctor_dtor_or_conv_p,
 					    /*parenthesized_p=*/NULL,
 					    /*member_p=*/true,
-					    /*friend_p=*/false);
+					    /*friend_p=*/false,
+					    /*static_p=*/false);
 		      peek = cp_lexer_peek_token (parser->lexer);
 		      if (cp_parser_error_occurred (parser))
 			break;
@@ -31034,7 +31058,8 @@ cp_parser_objc_class_ivars (cp_parser* parser)
 					&ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
 					/*member_p=*/false,
-					/*friend_p=*/false);
+					/*friend_p=*/false,
+					/*static_p=*/false);
 	    }
 
 	  /* Look for attributes that apply to the ivar.  */
@@ -31592,7 +31617,7 @@ cp_parser_objc_struct_declaration (cp_parser *parser)
       /* Parse the declarator.  */
       declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					 CP_PARSER_FLAGS_NONE,
-					 NULL, NULL, false, false);
+					 NULL, NULL, false, false, false);
 
       /* Look for attributes that apply to the ivar.  */
       attributes = cp_parser_attributes_opt (parser);
@@ -36225,7 +36250,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
 					 /*member_p=*/false,
-					 /*friend_p=*/false);
+					 /*friend_p=*/false,
+					 /*static_p=*/false);
       attributes = cp_parser_attributes_opt (parser);
       asm_specification = cp_parser_asm_specification_opt (parser);
 
diff --git gcc/cp/parser.h gcc/cp/parser.h
index 8bfa3f3b9c4..2377ddca813 100644
--- gcc/cp/parser.h
+++ gcc/cp/parser.h
@@ -282,9 +282,12 @@ struct GTY(()) cp_parser {
      been seen that makes the expression non-constant.  */
   bool non_integral_constant_expression_p;
 
-  /* TRUE if local variable names and `this' are forbidden in the
-     current context.  */
-  bool local_variables_forbidden_p;
+  /* Used to track if local variable names and/or `this' are forbidden
+     in the current context.  */
+#define LOCAL_VARS_FORBIDDEN (1 << 0)
+#define THIS_FORBIDDEN (1 << 1)
+#define LOCAL_VARS_AND_THIS_FORBIDDEN (LOCAL_VARS_FORBIDDEN | THIS_FORBIDDEN)
+  unsigned char local_variables_forbidden_p;
 
   /* TRUE if the declaration we are parsing is part of a
      linkage-specification of the form `extern string-literal
diff --git gcc/testsuite/g++.dg/cpp0x/this1.C gcc/testsuite/g++.dg/cpp0x/this1.C
new file mode 100644
index 00000000000..486e0450f4a
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/this1.C
@@ -0,0 +1,46 @@
+// PR c++/88548
+// { dg-do compile { target c++11 } }
+
+struct S1 {
+  int a;
+  auto m1 () -> decltype(this->a) { return 0; }
+  auto m2 () -> decltype(this) { return 0; }
+  void m3 () noexcept(noexcept(this->a)) { }
+  void m4 () noexcept(noexcept(this)) { }
+
+  static auto m5 () -> decltype(this->a) { return 0; } // { dg-error ".this. may not be used in this context" }
+  static auto m6 () -> decltype(this) { return 0; } // { dg-error ".this. may not be used in this context" }
+  static void m7 () noexcept(noexcept(this->a)) { } // { dg-error ".this. may not be used in this context" }
+  static void m8 () noexcept(noexcept(this)) { } // { dg-error ".this. may not be used in this context" }
+};
+
+template <typename T>
+struct S2 {
+  static auto f1(T arg) -> decltype((arg));
+};
+
+struct S3 {
+  int a;
+  void f1 () noexcept(noexcept(a)) { }
+  static void f2() noexcept(noexcept(a)) { }
+  static auto f3() -> decltype(a);
+  static auto f4() -> decltype((a));
+};
+
+template<typename T>
+class S4 {
+  T i;
+  friend int foo(const S4 &t) noexcept(noexcept(i)) { return t.i; }
+};
+
+void
+test ()
+{
+  S4<int> t;
+  foo(t);
+}
+
+struct S5 {
+  friend auto bar() -> decltype(this); // { dg-error ".this. may not be used in this context" }
+  auto bar2() -> decltype(this);
+};

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: C++ PATCH for c++/88548, this accepted in static member functions
  2018-12-23 10:30 C++ PATCH for c++/88548, this accepted in static member functions Marek Polacek
@ 2019-01-04 14:44 ` Marek Polacek
  2019-01-08  4:08 ` Jason Merrill
  1 sibling, 0 replies; 3+ messages in thread
From: Marek Polacek @ 2019-01-04 14:44 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

Ping.

On Sat, Dec 22, 2018 at 04:38:30PM -0500, Marek Polacek wrote:
> I noticed that we weren't diagnosing using 'this' in noexcept-specifiers
> of static member functions, and Jakub pointed out that this is also true
> for trailing-return-type.  cp_parser has local_variables_forbidden_p to
> detect using local vars and 'this' in certain contexts, so let's use that.
> 
> ...except that I found out that I need to be able to distinguish between
> forbidding just local vars and/or this, so I've changed its type to char.
> For instance, you can't use 'this' in a static member function declaration,
> but you can use a local var because noexcept/decltype is an unevaluated
> context.
> 
> I also noticed that we weren't diagnosing 'this' in a friend declaration,
> which is also forbidden.
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> 2018-12-22  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c++/88548 - this accepted in static member functions.
> 	* parser.c (cp_debug_parser): Adjust printing of
> 	local_variables_forbidden_p.
> 	(cp_parser_new): Set local_variables_forbidden_p to 0 rather than false.
> 	(cp_parser_primary_expression): When checking
> 	local_variables_forbidden_p, use THIS_FORBIDDEN or
> 	LOCAL_VARS_FORBIDDEN.
> 	(cp_parser_lambda_body): Update the type of
> 	local_variables_forbidden_p.  Set it to 0 rather than false.
> 	(cp_parser_condition): Adjust call to cp_parser_declarator.
> 	(cp_parser_explicit_instantiation): Likewise.
> 	(cp_parser_init_declarator): Likewise.
> 	(cp_parser_declarator): New parameter.  Use it.
> 	(cp_parser_direct_declarator): New parameter.  Use it to set
> 	local_variables_forbidden_p.  Adjust call to cp_parser_declarator.
> 	(cp_parser_type_id_1): Adjust call to cp_parser_declarator.
> 	(cp_parser_parameter_declaration): Likewise.
> 	(cp_parser_default_argument): Update the type of
> 	local_variables_forbidden_p.  Set it to LOCAL_VARS_AND_THIS_FORBIDDEN
> 	rather than true.
> 	(cp_parser_member_declaration): Tell cp_parser_declarator if we saw
> 	'static' or 'friend'.
> 	(cp_parser_exception_declaration): Adjust call to cp_parser_declarator.
> 	(cp_parser_late_parsing_default_args): Update the type of
> 	local_variables_forbidden_p.  Set it to LOCAL_VARS_AND_THIS_FORBIDDEN
> 	rather than true.
> 	(cp_parser_cache_defarg): Adjust call to cp_parser_declarator.
> 	(cp_parser_objc_class_ivars): Likewise.
> 	(cp_parser_objc_struct_declaration): Likewise.
> 	(cp_parser_omp_for_loop_init): Likewise.
> 	* parser.h (cp_parser): Change the type of local_variables_forbidden_p
> 	to unsigned char.
> 	(LOCAL_VARS_FORBIDDEN, LOCAL_VARS_AND_THIS_FORBIDDEN, THIS_FORBIDDEN):
> 	Define.
> 
> 	* g++.dg/cpp0x/this1.C: New test.
> 
> diff --git gcc/cp/parser.c gcc/cp/parser.c
> index 2cd91a37031..8aab21f3d33 100644
> --- gcc/cp/parser.c
> +++ gcc/cp/parser.c
> @@ -536,9 +536,12 @@ cp_debug_parser (FILE *file, cp_parser *parser)
>  			      parser->allow_non_integral_constant_expression_p);
>    cp_debug_print_flag (file, "Seen non-constant expression",
>  			      parser->non_integral_constant_expression_p);
> -  cp_debug_print_flag (file, "Local names and 'this' forbidden in "
> -			      "current context",
> -			      parser->local_variables_forbidden_p);
> +  cp_debug_print_flag (file, "Local names forbidden in current context",
> +			      (parser->local_variables_forbidden_p
> +			       & LOCAL_VARS_FORBIDDEN));
> +  cp_debug_print_flag (file, "'this' forbidden in current context",
> +			      (parser->local_variables_forbidden_p
> +			       & THIS_FORBIDDEN));
>    cp_debug_print_flag (file, "In unbraced linkage specification",
>  			      parser->in_unbraced_linkage_specification_p);
>    cp_debug_print_flag (file, "Parsing a declarator",
> @@ -2203,9 +2206,10 @@ static tree cp_parser_init_declarator
>     location_t *, tree *);
>  static cp_declarator *cp_parser_declarator
>    (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool *,
> -   bool, bool);
> +   bool, bool, bool);
>  static cp_declarator *cp_parser_direct_declarator
> -  (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool);
> +  (cp_parser *, cp_parser_declarator_kind, cp_parser_flags, int *, bool, bool,
> +   bool);
>  static enum tree_code cp_parser_ptr_operator
>    (cp_parser *, tree *, cp_cv_quals *, tree *);
>  static cp_cv_quals cp_parser_cv_qualifier_seq_opt
> @@ -3951,7 +3955,7 @@ cp_parser_new (void)
>    parser->non_integral_constant_expression_p = false;
>  
>    /* Local variable names are not forbidden.  */
> -  parser->local_variables_forbidden_p = false;
> +  parser->local_variables_forbidden_p = 0;
>  
>    /* We are not processing an `extern "C"' declaration.  */
>    parser->in_unbraced_linkage_specification_p = false;
> @@ -5405,7 +5409,7 @@ cp_parser_primary_expression (cp_parser *parser,
>  	  /* Recognize the `this' keyword.  */
>  	case RID_THIS:
>  	  cp_lexer_consume_token (parser->lexer);
> -	  if (parser->local_variables_forbidden_p)
> +	  if (parser->local_variables_forbidden_p & THIS_FORBIDDEN)
>  	    {
>  	      error_at (token->location,
>  			"%<this%> may not be used in this context");
> @@ -5681,14 +5685,14 @@ cp_parser_primary_expression (cp_parser *parser,
>  		      template <int N> struct A {
>  			int a[B<N>::i];
>  		      };
> -		     
> +
>  		   is accepted.  At template-instantiation time, we
>  		   will check that B<N>::i is actually a constant.  */
>  		return decl;
>  	      }
>  	    /* Check to see if DECL is a local variable in a context
>  	       where that is forbidden.  */
> -	    if (parser->local_variables_forbidden_p
> +	    if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN)
>  		&& local_variable_p (decl))
>  	      {
>  		error_at (id_expression.get_location (),
> @@ -10902,7 +10906,8 @@ static void
>  cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
>  {
>    bool nested = (current_function_decl != NULL_TREE);
> -  bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
> +  unsigned char local_variables_forbidden_p
> +    = parser->local_variables_forbidden_p;
>    bool in_function_body = parser->in_function_body;
>  
>    /* The body of a lambda-expression is not a subexpression of the enclosing
> @@ -10919,7 +10924,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
>    vec<tree> omp_privatization_save;
>    save_omp_privatization_clauses (omp_privatization_save);
>    /* Clear this in case we're in the middle of a default argument.  */
> -  parser->local_variables_forbidden_p = false;
> +  parser->local_variables_forbidden_p = 0;
>    parser->in_function_body = true;
>  
>    {
> @@ -11964,7 +11969,8 @@ cp_parser_condition (cp_parser* parser)
>  					 /*ctor_dtor_or_conv_p=*/NULL,
>  					 /*parenthesized_p=*/NULL,
>  					 /*member_p=*/false,
> -					 /*friend_p=*/false);
> +					 /*friend_p=*/false,
> +					 /*static_p=*/false);
>        /* Parse the attributes.  */
>        attributes = cp_parser_attributes_opt (parser);
>        /* Parse the asm-specification.  */
> @@ -17097,7 +17103,8 @@ cp_parser_explicit_instantiation (cp_parser* parser)
>  				/*ctor_dtor_or_conv_p=*/NULL,
>  				/*parenthesized_p=*/NULL,
>  				/*member_p=*/false,
> -				/*friend_p=*/false);
> +				/*friend_p=*/false,
> +				/*static_p=*/false);
>        if (declares_class_or_enum & 2)
>  	cp_parser_check_for_definition_in_return_type (declarator,
>  						       decl_specifiers.type,
> @@ -20042,7 +20049,7 @@ cp_parser_init_declarator (cp_parser* parser,
>      = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
>  			    flags, &ctor_dtor_or_conv_p,
>  			    /*parenthesized_p=*/NULL,
> -			    member_p, friend_p);
> +			    member_p, friend_p, /*static_p=*/false);
>    /* Gather up the deferred checks.  */
>    stop_deferring_access_checks ();
>  
> @@ -20460,7 +20467,9 @@ cp_parser_init_declarator (cp_parser* parser,
>  
>     MEMBER_P is true iff this declarator is a member-declarator.
>  
> -   FRIEND_P is true iff this declarator is a friend.  */
> +   FRIEND_P is true iff this declarator is a friend.
> +
> +   STATIC_P is true iff the keyword static was seen.  */
>  
>  static cp_declarator *
>  cp_parser_declarator (cp_parser* parser,
> @@ -20468,7 +20477,7 @@ cp_parser_declarator (cp_parser* parser,
>  		      cp_parser_flags flags,
>  		      int* ctor_dtor_or_conv_p,
>  		      bool* parenthesized_p,
> -		      bool member_p, bool friend_p)
> +		      bool member_p, bool friend_p, bool static_p)
>  {
>    cp_declarator *declarator;
>    enum tree_code code;
> @@ -20510,7 +20519,7 @@ cp_parser_declarator (cp_parser* parser,
>  					 /*ctor_dtor_or_conv_p=*/NULL,
>  					 /*parenthesized_p=*/NULL,
>  					 /*member_p=*/false,
> -					 friend_p);
> +					 friend_p, /*static_p=*/false);
>  
>        /* If we are parsing an abstract-declarator, we must handle the
>  	 case where the dependent declarator is absent.  */
> @@ -20529,7 +20538,7 @@ cp_parser_declarator (cp_parser* parser,
>  						   CPP_OPEN_PAREN);
>        declarator = cp_parser_direct_declarator (parser, dcl_kind,
>  						flags, ctor_dtor_or_conv_p,
> -						member_p, friend_p);
> +						member_p, friend_p, static_p);
>      }
>  
>    if (gnu_attributes && declarator && declarator != cp_error_declarator)
> @@ -20565,7 +20574,7 @@ cp_parser_declarator (cp_parser* parser,
>     of ambiguity we prefer an abstract declarator, as per
>     [dcl.ambig.res].
>     The parser flags FLAGS is used to control type-specifier parsing.
> -   CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are
> +   CTOR_DTOR_OR_CONV_P, MEMBER_P, FRIEND_P, and STATIC_P are
>     as for cp_parser_declarator.  */
>  
>  static cp_declarator *
> @@ -20573,7 +20582,7 @@ cp_parser_direct_declarator (cp_parser* parser,
>  			     cp_parser_declarator_kind dcl_kind,
>  			     cp_parser_flags flags,
>  			     int* ctor_dtor_or_conv_p,
> -			     bool member_p, bool friend_p)
> +			     bool member_p, bool friend_p, bool static_p)
>  {
>    cp_token *token;
>    cp_declarator *declarator = NULL;
> @@ -20676,6 +20685,11 @@ cp_parser_direct_declarator (cp_parser* parser,
>  		  tree attrs;
>  		  bool memfn = (member_p || (pushed_scope
>  					     && CLASS_TYPE_P (pushed_scope)));
> +		  unsigned char local_variables_forbidden_p
> +		    = parser->local_variables_forbidden_p;
> +		  /* 'this' is not allowed in static member functions.  */
> +		  if (static_p || friend_p)
> +		    parser->local_variables_forbidden_p |= THIS_FORBIDDEN;
>  
>  		  is_declarator = true;
>  
> @@ -20723,6 +20737,10 @@ cp_parser_direct_declarator (cp_parser* parser,
>  		     return type, so are not those of the declared
>  		     function.  */
>  		  parser->default_arg_ok_p = false;
> +
> +		  /* Restore the state of local_variables_forbidden_p.  */
> +		  parser->local_variables_forbidden_p
> +		    = local_variables_forbidden_p;
>  		}
>  
>  	      /* Remove the function parms from scope.  */
> @@ -20753,7 +20771,8 @@ cp_parser_direct_declarator (cp_parser* parser,
>  		= cp_parser_declarator (parser, dcl_kind, flags,
>  					ctor_dtor_or_conv_p,
>  					/*parenthesized_p=*/NULL,
> -					member_p, friend_p);
> +					member_p, friend_p,
> +					/*static_p=*/false);
>  	      parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
>  	      first = false;
>  	      /* Expect a `)'.  */
> @@ -21647,7 +21666,8 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
>  			    CP_PARSER_FLAGS_NONE, NULL,
>  			    /*parenthesized_p=*/NULL,
>  			    /*member_p=*/false,
> -			    /*friend_p=*/false);
> +			    /*friend_p=*/false,
> +			    /*static_p=*/false);
>    /* Check to see if there really was a declarator.  */
>    if (!cp_parser_parse_definitely (parser))
>      abstract_declarator = NULL;
> @@ -22232,7 +22252,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
>  					 /*ctor_dtor_or_conv_p=*/NULL,
>  					 parenthesized_p,
>  					 /*member_p=*/false,
> -					 /*friend_p=*/false);
> +					 /*friend_p=*/false,
> +					 /*static_p=*/false);
>        parser->default_arg_ok_p = saved_default_arg_ok_p;
>        /* After the declarator, allow more attributes.  */
>        decl_specifiers.attributes
> @@ -22413,7 +22434,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
>  {
>    tree default_argument = NULL_TREE;
>    bool saved_greater_than_is_operator_p;
> -  bool saved_local_variables_forbidden_p;
> +  unsigned char saved_local_variables_forbidden_p;
>    bool non_constant_p, is_direct_init;
>  
>    /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
> @@ -22423,7 +22444,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
>    /* Local variable names (and the `this' keyword) may not
>       appear in a default argument.  */
>    saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
> -  parser->local_variables_forbidden_p = true;
> +  parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
>    /* Parse the assignment-expression.  */
>    if (template_parm_p)
>      push_deferring_access_checks (dk_no_deferred);
> @@ -24442,6 +24463,7 @@ cp_parser_member_declaration (cp_parser* parser)
>  	      cp_declarator *declarator;
>  	      tree asm_specification;
>  	      int ctor_dtor_or_conv_p;
> +	      bool static_p = (decl_specifiers.storage_class == sc_static);
>  
>  	      /* Parse the declarator.  */
>  	      declarator
> @@ -24450,7 +24472,7 @@ cp_parser_member_declaration (cp_parser* parser)
>  					&ctor_dtor_or_conv_p,
>  					/*parenthesized_p=*/NULL,
>  					/*member_p=*/true,
> -					friend_p);
> +					friend_p, static_p);
>  
>  	      /* If something went wrong parsing the declarator, make sure
>  		 that we at least consume some tokens.  */
> @@ -25331,7 +25353,8 @@ cp_parser_exception_declaration (cp_parser* parser)
>  				       /*ctor_dtor_or_conv_p=*/NULL,
>  				       /*parenthesized_p=*/NULL,
>  				       /*member_p=*/false,
> -				       /*friend_p=*/false);
> +				       /*friend_p=*/false,
> +				       /*static_p=*/false);
>  
>    /* Restore the saved message.  */
>    parser->type_definition_forbidden_message = saved_message;
> @@ -28576,7 +28599,7 @@ cp_parser_late_parsing_nsdmi (cp_parser *parser, tree field)
>  static void
>  cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
>  {
> -  bool saved_local_variables_forbidden_p;
> +  unsigned char saved_local_variables_forbidden_p;
>    tree parm, parmdecl;
>  
>    /* While we're parsing the default args, we might (due to the
> @@ -28588,7 +28611,7 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
>    /* Local variable names (and the `this' keyword) may not appear
>       in a default argument.  */
>    saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
> -  parser->local_variables_forbidden_p = true;
> +  parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN;
>  
>    push_defarg_context (fn);
>  
> @@ -29667,7 +29690,8 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
>  					    &ctor_dtor_or_conv_p,
>  					    /*parenthesized_p=*/NULL,
>  					    /*member_p=*/true,
> -					    /*friend_p=*/false);
> +					    /*friend_p=*/false,
> +					    /*static_p=*/false);
>  		      peek = cp_lexer_peek_token (parser->lexer);
>  		      if (cp_parser_error_occurred (parser))
>  			break;
> @@ -31034,7 +31058,8 @@ cp_parser_objc_class_ivars (cp_parser* parser)
>  					&ctor_dtor_or_conv_p,
>  					/*parenthesized_p=*/NULL,
>  					/*member_p=*/false,
> -					/*friend_p=*/false);
> +					/*friend_p=*/false,
> +					/*static_p=*/false);
>  	    }
>  
>  	  /* Look for attributes that apply to the ivar.  */
> @@ -31592,7 +31617,7 @@ cp_parser_objc_struct_declaration (cp_parser *parser)
>        /* Parse the declarator.  */
>        declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
>  					 CP_PARSER_FLAGS_NONE,
> -					 NULL, NULL, false, false);
> +					 NULL, NULL, false, false, false);
>  
>        /* Look for attributes that apply to the ivar.  */
>        attributes = cp_parser_attributes_opt (parser);
> @@ -36225,7 +36250,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser,
>  					 /*ctor_dtor_or_conv_p=*/NULL,
>  					 /*parenthesized_p=*/NULL,
>  					 /*member_p=*/false,
> -					 /*friend_p=*/false);
> +					 /*friend_p=*/false,
> +					 /*static_p=*/false);
>        attributes = cp_parser_attributes_opt (parser);
>        asm_specification = cp_parser_asm_specification_opt (parser);
>  
> diff --git gcc/cp/parser.h gcc/cp/parser.h
> index 8bfa3f3b9c4..2377ddca813 100644
> --- gcc/cp/parser.h
> +++ gcc/cp/parser.h
> @@ -282,9 +282,12 @@ struct GTY(()) cp_parser {
>       been seen that makes the expression non-constant.  */
>    bool non_integral_constant_expression_p;
>  
> -  /* TRUE if local variable names and `this' are forbidden in the
> -     current context.  */
> -  bool local_variables_forbidden_p;
> +  /* Used to track if local variable names and/or `this' are forbidden
> +     in the current context.  */
> +#define LOCAL_VARS_FORBIDDEN (1 << 0)
> +#define THIS_FORBIDDEN (1 << 1)
> +#define LOCAL_VARS_AND_THIS_FORBIDDEN (LOCAL_VARS_FORBIDDEN | THIS_FORBIDDEN)
> +  unsigned char local_variables_forbidden_p;
>  
>    /* TRUE if the declaration we are parsing is part of a
>       linkage-specification of the form `extern string-literal
> diff --git gcc/testsuite/g++.dg/cpp0x/this1.C gcc/testsuite/g++.dg/cpp0x/this1.C
> new file mode 100644
> index 00000000000..486e0450f4a
> --- /dev/null
> +++ gcc/testsuite/g++.dg/cpp0x/this1.C
> @@ -0,0 +1,46 @@
> +// PR c++/88548
> +// { dg-do compile { target c++11 } }
> +
> +struct S1 {
> +  int a;
> +  auto m1 () -> decltype(this->a) { return 0; }
> +  auto m2 () -> decltype(this) { return 0; }
> +  void m3 () noexcept(noexcept(this->a)) { }
> +  void m4 () noexcept(noexcept(this)) { }
> +
> +  static auto m5 () -> decltype(this->a) { return 0; } // { dg-error ".this. may not be used in this context" }
> +  static auto m6 () -> decltype(this) { return 0; } // { dg-error ".this. may not be used in this context" }
> +  static void m7 () noexcept(noexcept(this->a)) { } // { dg-error ".this. may not be used in this context" }
> +  static void m8 () noexcept(noexcept(this)) { } // { dg-error ".this. may not be used in this context" }
> +};
> +
> +template <typename T>
> +struct S2 {
> +  static auto f1(T arg) -> decltype((arg));
> +};
> +
> +struct S3 {
> +  int a;
> +  void f1 () noexcept(noexcept(a)) { }
> +  static void f2() noexcept(noexcept(a)) { }
> +  static auto f3() -> decltype(a);
> +  static auto f4() -> decltype((a));
> +};
> +
> +template<typename T>
> +class S4 {
> +  T i;
> +  friend int foo(const S4 &t) noexcept(noexcept(i)) { return t.i; }
> +};
> +
> +void
> +test ()
> +{
> +  S4<int> t;
> +  foo(t);
> +}
> +
> +struct S5 {
> +  friend auto bar() -> decltype(this); // { dg-error ".this. may not be used in this context" }
> +  auto bar2() -> decltype(this);
> +};

Marek

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: C++ PATCH for c++/88548, this accepted in static member functions
  2018-12-23 10:30 C++ PATCH for c++/88548, this accepted in static member functions Marek Polacek
  2019-01-04 14:44 ` Marek Polacek
@ 2019-01-08  4:08 ` Jason Merrill
  1 sibling, 0 replies; 3+ messages in thread
From: Jason Merrill @ 2019-01-08  4:08 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches

On 12/22/18 4:38 PM, Marek Polacek wrote:
> I noticed that we weren't diagnosing using 'this' in noexcept-specifiers
> of static member functions, and Jakub pointed out that this is also true
> for trailing-return-type.  cp_parser has local_variables_forbidden_p to
> detect using local vars and 'this' in certain contexts, so let's use that.
> 
> ...except that I found out that I need to be able to distinguish between
> forbidding just local vars and/or this, so I've changed its type to char.
> For instance, you can't use 'this' in a static member function declaration,
> but you can use a local var because noexcept/decltype is an unevaluated
> context.
> 
> I also noticed that we weren't diagnosing 'this' in a friend declaration,
> which is also forbidden.
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?

I wonder about suppressing inject_this_parm for a static member 
function, since current_class_ptr is unset within a static member 
function.  But this approach (and patch) is also OK.

Jason

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-01-08  4:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-23 10:30 C++ PATCH for c++/88548, this accepted in static member functions Marek Polacek
2019-01-04 14:44 ` Marek Polacek
2019-01-08  4:08 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).