PR c++/88548 - this accepted in static member functions.
authorMarek Polacek <polacek@redhat.com>
Tue, 8 Jan 2019 17:37:51 +0000 (17:37 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Tue, 8 Jan 2019 17:37:51 +0000 (17:37 +0000)
* 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.

From-SVN: r267731

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/cp/parser.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/this1.C [new file with mode: 0644]

index f8d3d93984858b32973da84eeff353c14ad1195b..f3b5dbe68bc31ff401b005aa063fceca3526b612 100644 (file)
@@ -1,3 +1,40 @@
+2019-01-08  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.
+
 2019-01-08  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * decl.c (start_decl): Improve permerror location.
index bca1739ace39cc769e29372e6be8ef97cc1d3a0f..ca75c010e22e32fe25ad777a3d50596d5b3bf08a 100644 (file)
@@ -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 (),
@@ -10928,7 +10932,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
@@ -10945,7 +10950,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;
 
   {
@@ -11990,7 +11995,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.  */
@@ -17123,7 +17129,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,
@@ -20068,7 +20075,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 ();
 
@@ -20486,7 +20493,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,
@@ -20494,7 +20503,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;
@@ -20536,7 +20545,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.  */
@@ -20555,7 +20564,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)
@@ -20591,7 +20600,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 *
@@ -20599,7 +20608,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;
@@ -20702,6 +20711,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;
 
@@ -20749,6 +20763,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.  */
@@ -20779,7 +20797,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 `)'.  */
@@ -21673,7 +21692,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;
@@ -22258,7 +22278,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
@@ -22439,7 +22460,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
@@ -22449,7 +22470,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);
@@ -24468,6 +24489,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
@@ -24476,7 +24498,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.  */
@@ -25357,7 +25379,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;
@@ -28602,7 +28625,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
@@ -28614,7 +28637,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);
 
@@ -29693,7 +29716,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;
@@ -31060,7 +31084,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.  */
@@ -31618,7 +31643,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);
@@ -36251,7 +36276,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);
 
index 81abb69ef3de00e4222e0fcb2631b449ac2ab482..1d6cb2d424c8eb1819844e31dfa5b47058d03676 100644 (file)
@@ -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
index c53bf5a6ee77275fb0a858fdc9add61d3dd61127..4a70997cbedd6a602aa7c861bcf816d5b2aa30bc 100644 (file)
@@ -1,3 +1,8 @@
+2019-01-08  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/88548 - this accepted in static member functions.
+       * g++.dg/cpp0x/this1.C: New test.
+
 2019-01-08  Martin Liska  <mliska@suse.cz>
 
        PR tree-optimization/88753
diff --git a/gcc/testsuite/g++.dg/cpp0x/this1.C b/gcc/testsuite/g++.dg/cpp0x/this1.C
new file mode 100644 (file)
index 0000000..486e045
--- /dev/null
@@ -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);
+};