* 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).