From e01ffb47c6fec6d52f254390bf863b4ca0fa32e2 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 8 Jan 2019 17:37:51 +0000 Subject: [PATCH] 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. From-SVN: r267731 --- gcc/cp/ChangeLog | 37 ++++++++++++ gcc/cp/parser.c | 92 +++++++++++++++++++----------- gcc/cp/parser.h | 9 ++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/cpp0x/this1.C | 46 +++++++++++++++ 5 files changed, 153 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/this1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f8d3d939848..f3b5dbe68bc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +2019-01-08 Marek Polacek + + 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 * decl.c (start_decl): Improve permerror location. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bca1739ace3..ca75c010e22 100644 --- a/gcc/cp/parser.c +++ b/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, "% may not be used in this context"); @@ -5681,14 +5685,14 @@ cp_parser_primary_expression (cp_parser *parser, template struct A { int a[B::i]; }; - + is accepted. At template-instantiation time, we will check that B::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 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); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 81abb69ef3d..1d6cb2d424c 100644 --- a/gcc/cp/parser.h +++ b/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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c53bf5a6ee7..4a70997cbed 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-01-08 Marek Polacek + + PR c++/88548 - this accepted in static member functions. + * g++.dg/cpp0x/this1.C: New test. + 2019-01-08 Martin Liska 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 index 00000000000..486e0450f4a --- /dev/null +++ b/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 +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 +class S4 { + T i; + friend int foo(const S4 &t) noexcept(noexcept(i)) { return t.i; } +}; + +void +test () +{ + S4 t; + foo(t); +} + +struct S5 { + friend auto bar() -> decltype(this); // { dg-error ".this. may not be used in this context" } + auto bar2() -> decltype(this); +}; -- 2.30.2