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 <pola...@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