vkd3d-shader/hlsl: Validate break/continue context.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
This commit is contained in:
Nikolay Sivov 2023-10-24 21:05:42 +02:00 committed by Alexandre Julliard
parent 9a6e4a0c58
commit 72623031a2
Notes: Alexandre Julliard 2023-10-31 22:37:53 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Zebediah Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/361
3 changed files with 34 additions and 16 deletions

View File

@ -727,6 +727,8 @@ struct hlsl_scope
struct hlsl_scope *upper; struct hlsl_scope *upper;
/* The scope was created for the loop statement. */ /* The scope was created for the loop statement. */
bool loop; bool loop;
/* The scope was created for the switch statement. */
bool _switch;
}; };
struct hlsl_profile_info struct hlsl_profile_info

View File

@ -4640,12 +4640,31 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type
} }
} }
static struct hlsl_scope *get_loop_scope(struct hlsl_scope *scope) static bool check_continue(struct hlsl_ctx *ctx, const struct hlsl_scope *scope, const struct vkd3d_shader_location *loc)
{ {
if (scope->loop) if (scope->_switch)
return scope; {
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'continue' statement is not allowed in 'switch' statements.");
return false;
}
return scope->upper ? get_loop_scope(scope->upper) : NULL; if (scope->loop)
return true;
if (scope->upper)
return check_continue(ctx, scope->upper, loc);
hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "The 'continue' statement is only allowed in loops.");
return false;
}
static bool is_break_allowed(const struct hlsl_scope *scope)
{
if (scope->loop || scope->_switch)
return true;
return scope->upper ? is_break_allowed(scope->upper) : false;
} }
static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hlsl_ir_switch_case *check, struct list *cases) static void check_duplicated_switch_cases(struct hlsl_ctx *ctx, const struct hlsl_ir_switch_case *check, struct list *cases)
@ -5407,6 +5426,8 @@ loop_scope_start:
switch_scope_start: switch_scope_start:
%empty %empty
{ {
hlsl_push_scope(ctx);
ctx->cur_scope->_switch = true;
} }
var_identifier: var_identifier:
@ -6244,12 +6265,10 @@ jump_statement:
{ {
struct hlsl_ir_node *jump; struct hlsl_ir_node *jump;
/* TODO: allow 'break' in the 'switch' statements. */ if (!is_break_allowed(ctx->cur_scope))
if (!get_loop_scope(ctx->cur_scope))
{ {
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'break' statement must be used inside of a loop."); "The 'break' statement must be used inside of a loop or a switch.");
} }
if (!($$ = make_empty_block(ctx))) if (!($$ = make_empty_block(ctx)))
@ -6261,13 +6280,8 @@ jump_statement:
| KW_CONTINUE ';' | KW_CONTINUE ';'
{ {
struct hlsl_ir_node *jump; struct hlsl_ir_node *jump;
struct hlsl_scope *scope;
if (!(scope = get_loop_scope(ctx->cur_scope))) check_continue(ctx, ctx->cur_scope, &@1);
{
hlsl_error(ctx, &@1, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX,
"The 'continue' statement must be used inside of a loop.");
}
if (!($$ = make_empty_block(ctx))) if (!($$ = make_empty_block(ctx)))
YYABORT; YYABORT;
@ -6411,6 +6425,8 @@ switch_statement:
$$ = $5; $$ = $5;
hlsl_block_add_instr($$, s); hlsl_block_add_instr($$, s);
hlsl_pop_scope(ctx);
} }
switch_case: switch_case:

View File

@ -211,7 +211,7 @@ float4 main() : sv_target
} }
% unterminated cases % unterminated cases
[pixel shader fail(sm<6)] [pixel shader fail(sm<6) todo]
uint4 v; uint4 v;
float4 main() : sv_target float4 main() : sv_target
@ -455,7 +455,7 @@ todo draw quad
probe all rgba (1.0, 2.0, 3.0, 4.0) probe all rgba (1.0, 2.0, 3.0, 4.0)
% 'continue' is not supported in switches % 'continue' is not supported in switches
[pixel shader fail(sm<6) todo] [pixel shader fail(sm<6)]
uint4 v; uint4 v;
float4 main() : sv_target float4 main() : sv_target