[Bug #20647] Disallow return
directly within a singleton class
This commit is contained in:
parent
f2f9d6ce49
commit
e642ddf7ae
Notes:
git
2024-07-24 06:32:02 +00:00
12
parse.y
12
parse.y
@ -318,6 +318,7 @@ struct lex_context {
|
|||||||
unsigned int in_class: 1;
|
unsigned int in_class: 1;
|
||||||
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
|
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
|
||||||
BITFIELD(enum rescue_context, in_rescue, 2);
|
BITFIELD(enum rescue_context, in_rescue, 2);
|
||||||
|
unsigned int cant_return: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
|
typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
|
||||||
@ -1696,12 +1697,17 @@ endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
|
|||||||
#define begin_definition(k, loc_beg, loc_end) \
|
#define begin_definition(k, loc_beg, loc_end) \
|
||||||
do { \
|
do { \
|
||||||
if (!(p->ctxt.in_class = (k)[0] != 0)) { \
|
if (!(p->ctxt.in_class = (k)[0] != 0)) { \
|
||||||
|
/* singleton class */ \
|
||||||
|
p->ctxt.cant_return = !p->ctxt.in_def; \
|
||||||
p->ctxt.in_def = 0; \
|
p->ctxt.in_def = 0; \
|
||||||
} \
|
} \
|
||||||
else if (p->ctxt.in_def) { \
|
else if (p->ctxt.in_def) { \
|
||||||
YYLTYPE loc = code_loc_gen(loc_beg, loc_end); \
|
YYLTYPE loc = code_loc_gen(loc_beg, loc_end); \
|
||||||
yyerror1(&loc, k " definition in method body"); \
|
yyerror1(&loc, k " definition in method body"); \
|
||||||
} \
|
} \
|
||||||
|
else { \
|
||||||
|
p->ctxt.cant_return = 1; \
|
||||||
|
} \
|
||||||
local_push(p, 0); \
|
local_push(p, 0); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -3400,6 +3406,7 @@ def_name : fname
|
|||||||
local_push(p, 0);
|
local_push(p, 0);
|
||||||
p->ctxt.in_def = 1;
|
p->ctxt.in_def = 1;
|
||||||
p->ctxt.in_rescue = before_rescue;
|
p->ctxt.in_rescue = before_rescue;
|
||||||
|
p->ctxt.cant_return = 0;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -4628,6 +4635,7 @@ primary : literal
|
|||||||
/*% ripper: class!($:cpath, $:superclass, $:bodystmt) %*/
|
/*% ripper: class!($:cpath, $:superclass, $:bodystmt) %*/
|
||||||
local_pop(p);
|
local_pop(p);
|
||||||
p->ctxt.in_class = $k_class.in_class;
|
p->ctxt.in_class = $k_class.in_class;
|
||||||
|
p->ctxt.cant_return = $k_class.cant_return;
|
||||||
p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
|
p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
|
||||||
}
|
}
|
||||||
| k_class tLSHFT expr_value
|
| k_class tLSHFT expr_value
|
||||||
@ -4646,6 +4654,7 @@ primary : literal
|
|||||||
local_pop(p);
|
local_pop(p);
|
||||||
p->ctxt.in_def = $k_class.in_def;
|
p->ctxt.in_def = $k_class.in_def;
|
||||||
p->ctxt.in_class = $k_class.in_class;
|
p->ctxt.in_class = $k_class.in_class;
|
||||||
|
p->ctxt.cant_return = $k_class.cant_return;
|
||||||
p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
|
p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
|
||||||
}
|
}
|
||||||
| k_module cpath
|
| k_module cpath
|
||||||
@ -4662,6 +4671,7 @@ primary : literal
|
|||||||
/*% ripper: module!($:cpath, $:bodystmt) %*/
|
/*% ripper: module!($:cpath, $:bodystmt) %*/
|
||||||
local_pop(p);
|
local_pop(p);
|
||||||
p->ctxt.in_class = $k_module.in_class;
|
p->ctxt.in_class = $k_module.in_class;
|
||||||
|
p->ctxt.cant_return = $k_module.cant_return;
|
||||||
p->ctxt.shareable_constant_value = $k_module.shareable_constant_value;
|
p->ctxt.shareable_constant_value = $k_module.shareable_constant_value;
|
||||||
}
|
}
|
||||||
| defn_head[head]
|
| defn_head[head]
|
||||||
@ -4890,7 +4900,7 @@ k_end : keyword_end
|
|||||||
|
|
||||||
k_return : keyword_return
|
k_return : keyword_return
|
||||||
{
|
{
|
||||||
if (p->ctxt.in_class && !p->ctxt.in_def && !dyna_in_block(p))
|
if (p->ctxt.cant_return && !dyna_in_block(p))
|
||||||
yyerror1(&@1, "Invalid return in class/module body");
|
yyerror1(&@1, "Invalid return in class/module body");
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -15342,6 +15342,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
parse_return(pm_parser_t *parser, pm_node_t *node) {
|
parse_return(pm_parser_t *parser, pm_node_t *node) {
|
||||||
|
bool in_sclass = false;
|
||||||
for (pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
|
for (pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
|
||||||
switch (context_node->context) {
|
switch (context_node->context) {
|
||||||
case PM_CONTEXT_BEGIN_ELSE:
|
case PM_CONTEXT_BEGIN_ELSE:
|
||||||
@ -15366,10 +15367,6 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
|
|||||||
case PM_CONTEXT_PREDICATE:
|
case PM_CONTEXT_PREDICATE:
|
||||||
case PM_CONTEXT_PREEXE:
|
case PM_CONTEXT_PREEXE:
|
||||||
case PM_CONTEXT_RESCUE_MODIFIER:
|
case PM_CONTEXT_RESCUE_MODIFIER:
|
||||||
case PM_CONTEXT_SCLASS_ELSE:
|
|
||||||
case PM_CONTEXT_SCLASS_ENSURE:
|
|
||||||
case PM_CONTEXT_SCLASS_RESCUE:
|
|
||||||
case PM_CONTEXT_SCLASS:
|
|
||||||
case PM_CONTEXT_TERNARY:
|
case PM_CONTEXT_TERNARY:
|
||||||
case PM_CONTEXT_UNLESS:
|
case PM_CONTEXT_UNLESS:
|
||||||
case PM_CONTEXT_UNTIL:
|
case PM_CONTEXT_UNTIL:
|
||||||
@ -15377,6 +15374,12 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
|
|||||||
// Keep iterating up the lists of contexts, because returns can
|
// Keep iterating up the lists of contexts, because returns can
|
||||||
// see through these.
|
// see through these.
|
||||||
continue;
|
continue;
|
||||||
|
case PM_CONTEXT_SCLASS_ELSE:
|
||||||
|
case PM_CONTEXT_SCLASS_ENSURE:
|
||||||
|
case PM_CONTEXT_SCLASS_RESCUE:
|
||||||
|
case PM_CONTEXT_SCLASS:
|
||||||
|
in_sclass = true;
|
||||||
|
continue;
|
||||||
case PM_CONTEXT_CLASS_ELSE:
|
case PM_CONTEXT_CLASS_ELSE:
|
||||||
case PM_CONTEXT_CLASS_ENSURE:
|
case PM_CONTEXT_CLASS_ENSURE:
|
||||||
case PM_CONTEXT_CLASS_RESCUE:
|
case PM_CONTEXT_CLASS_RESCUE:
|
||||||
@ -15411,6 +15414,9 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in_sclass) {
|
||||||
|
pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
class << A; return; end
|
||||||
|
^~~~~~ Invalid return in class/module body
|
||||||
|
|
@ -316,6 +316,7 @@ class TestClass < Test::Unit::TestCase
|
|||||||
|
|
||||||
def test_invalid_return_from_class_definition
|
def test_invalid_return_from_class_definition
|
||||||
assert_syntax_error("class C; return; end", /Invalid return/)
|
assert_syntax_error("class C; return; end", /Invalid return/)
|
||||||
|
assert_syntax_error("class << Object; return; end", /Invalid return/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_invalid_yield_from_class_definition
|
def test_invalid_yield_from_class_definition
|
||||||
|
Loading…
x
Reference in New Issue
Block a user