https://github.com/python/cpython/commit/dd7ffdbbff35d9a86906c71ee2c15a1cee02701d
commit: dd7ffdbbff35d9a86906c71ee2c15a1cee02701d
branch: 3.13
author: Bénédikt Tran <10796600+picn...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-06-10T09:12:41Z
summary:

[3.13] gh-133157: fix UBSan failures in `Parser/pegen.c` (GH-134048) (#135334)

[3.13] gh-133157: fix UBSan failures in `Parser/pegen.c` (GH-134048)
(cherry picked from commit 754e7c9b5187fcad22acf7555479603f173a4a09)

files:
M Parser/parser.c
M Parser/pegen.c
M Parser/pegen.h
M Tools/peg_generator/pegen/c_generator.py

diff --git a/Parser/parser.c b/Parser/parser.c
index 2d93b35e71e0be..cb43d5c5c3234f 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -1808,7 +1808,7 @@ simple_stmt_rule(Parser *p)
         D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "&('import' | 'from') import_stmt"));
         stmt_ty import_stmt_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_6_rule, p)
+            _PyPegen_lookahead(1, _tmp_6_rule, p)
             &&
             (import_stmt_var = import_stmt_rule(p))  // import_stmt
         )
@@ -2082,7 +2082,7 @@ compound_stmt_rule(Parser *p)
         D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "&('def' | '@' | 'async') function_def"));
         stmt_ty function_def_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_7_rule, p)
+            _PyPegen_lookahead(1, _tmp_7_rule, p)
             &&
             (function_def_var = function_def_rule(p))  // function_def
         )
@@ -2124,7 +2124,7 @@ compound_stmt_rule(Parser *p)
         D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "&('class' | '@') class_def"));
         stmt_ty class_def_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_8_rule, p)
+            _PyPegen_lookahead(1, _tmp_8_rule, p)
             &&
             (class_def_var = class_def_rule(p))  // class_def
         )
@@ -2145,7 +2145,7 @@ compound_stmt_rule(Parser *p)
         D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "&('with' | 'async') with_stmt"));
         stmt_ty with_stmt_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_9_rule, p)
+            _PyPegen_lookahead(1, _tmp_9_rule, p)
             &&
             (with_stmt_var = with_stmt_rule(p))  // with_stmt
         )
@@ -2166,7 +2166,7 @@ compound_stmt_rule(Parser *p)
         D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', 
_mark, p->mark, "&('for' | 'async') for_stmt"));
         stmt_ty for_stmt_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_10_rule, p)
+            _PyPegen_lookahead(1, _tmp_10_rule, p)
             &&
             (for_stmt_var = for_stmt_rule(p))  // for_stmt
         )
@@ -3197,7 +3197,7 @@ del_stmt_rule(Parser *p)
             &&
             (a = del_targets_rule(p))  // del_targets
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_22_rule, p)
+            _PyPegen_lookahead(1, _tmp_22_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ del_stmt[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "'del' del_targets &(';' | NEWLINE)"));
@@ -6802,7 +6802,7 @@ with_item_rule(Parser *p)
             &&
             (t = star_target_rule(p))  // star_target
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_59_rule, p)
+            _PyPegen_lookahead(1, _tmp_59_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | 
':')"));
@@ -8207,7 +8207,7 @@ literal_pattern_rule(Parser *p)
         if (
             (value = signed_number_rule(p))  // signed_number
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_67_rule, p)
+            _PyPegen_lookahead(0, _tmp_67_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')"));
@@ -8441,7 +8441,7 @@ literal_expr_rule(Parser *p)
         if (
             (signed_number_var = signed_number_rule(p))  // signed_number
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_68_rule, p)
+            _PyPegen_lookahead(0, _tmp_68_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')"));
@@ -9041,7 +9041,7 @@ pattern_capture_target_rule(Parser *p)
             &&
             (name = _PyPegen_name_token(p))  // NAME
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_69_rule, p)
+            _PyPegen_lookahead(0, _tmp_69_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | 
'=')"));
@@ -9156,7 +9156,7 @@ value_pattern_rule(Parser *p)
         if (
             (attr = attr_rule(p))  // attr
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_70_rule, p)
+            _PyPegen_lookahead(0, _tmp_70_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')"));
@@ -14857,7 +14857,7 @@ atom_rule(Parser *p)
         D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, 
p->mark, "&(STRING | FSTRING_START) strings"));
         expr_ty strings_var;
         if (
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_93_rule, p)
+            _PyPegen_lookahead(1, _tmp_93_rule, p)
             &&
             (strings_var = strings_rule(p))  // strings
         )
@@ -18466,7 +18466,7 @@ target_with_star_atom_rule(Parser *p)
             &&
             (b = _PyPegen_name_token(p))  // NAME
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME 
!t_lookahead"));
@@ -18510,7 +18510,7 @@ target_with_star_atom_rule(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 10))  // token=']'
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' 
!t_lookahead"));
@@ -18857,7 +18857,7 @@ single_subscript_attribute_target_rule(Parser *p)
             &&
             (b = _PyPegen_name_token(p))  // NAME
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ single_subscript_attribute_target[%d-%d]: 
%s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME 
!t_lookahead"));
@@ -18901,7 +18901,7 @@ single_subscript_attribute_target_rule(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 10))  // token=']'
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ single_subscript_attribute_target[%d-%d]: 
%s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' 
!t_lookahead"));
@@ -19011,7 +19011,7 @@ t_primary_raw(Parser *p)
             &&
             (b = _PyPegen_name_token(p))  // NAME
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(1, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ t_primary[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary '.' NAME &t_lookahead"));
@@ -19055,7 +19055,7 @@ t_primary_raw(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 10))  // token=']'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(1, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ t_primary[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' &t_lookahead"));
@@ -19093,7 +19093,7 @@ t_primary_raw(Parser *p)
             &&
             (b = genexp_rule(p))  // genexp
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(1, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ t_primary[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary genexp &t_lookahead"));
@@ -19137,7 +19137,7 @@ t_primary_raw(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 8))  // token=')'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(1, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ t_primary[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary '(' arguments? ')' &t_lookahead"));
@@ -19172,7 +19172,7 @@ t_primary_raw(Parser *p)
         if (
             (a = atom_rule(p))  // atom
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(1, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ t_primary[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "atom &t_lookahead"));
@@ -19362,7 +19362,7 @@ del_target_rule(Parser *p)
             &&
             (b = _PyPegen_name_token(p))  // NAME
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ del_target[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
@@ -19406,7 +19406,7 @@ del_target_rule(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 10))  // token=']'
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) t_lookahead_rule, p)
+            _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ del_target[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
@@ -19894,7 +19894,7 @@ func_type_comment_rule(Parser *p)
             &&
             (t = _PyPegen_expect_token(p, TYPE_COMMENT))  // 
token='TYPE_COMMENT'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_149_rule, p)
+            _PyPegen_lookahead(1, _tmp_149_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE 
INDENT)"));
@@ -20088,7 +20088,7 @@ invalid_arguments_rule(Parser *p)
             &&
             (b = _PyPegen_expect_token(p, 22))  // token='='
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_155_rule, p)
+            _PyPegen_lookahead(1, _tmp_155_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | 
')')"));
@@ -20286,7 +20286,7 @@ invalid_kwarg_rule(Parser *p)
         expr_ty a;
         Token * b;
         if (
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_157_rule, p)
+            _PyPegen_lookahead(0, _tmp_157_rule, p)
             &&
             (a = expression_rule(p))  // expression
             &&
@@ -20542,7 +20542,7 @@ invalid_expression_rule(Parser *p)
         expr_ty a;
         expr_ty b;
         if (
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_158_rule, p)
+            _PyPegen_lookahead(0, _tmp_158_rule, p)
             &&
             (a = disjunction_rule(p))  // disjunction
             &&
@@ -20578,7 +20578,7 @@ invalid_expression_rule(Parser *p)
             &&
             (b = disjunction_rule(p))  // disjunction
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_159_rule, p)
+            _PyPegen_lookahead(0, _tmp_159_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 
!('else' | ':')"));
@@ -20699,7 +20699,7 @@ invalid_named_expression_rule(Parser *p)
             &&
             (b = bitwise_or_rule(p))  // bitwise_or
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_160_rule, p)
+            _PyPegen_lookahead(0, _tmp_160_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | 
':=')"));
@@ -20725,7 +20725,7 @@ invalid_named_expression_rule(Parser *p)
         Token * b;
         expr_ty bitwise_or_var;
         if (
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_161_rule, p)
+            _PyPegen_lookahead(0, _tmp_161_rule, p)
             &&
             (a = bitwise_or_rule(p))  // bitwise_or
             &&
@@ -20733,7 +20733,7 @@ invalid_named_expression_rule(Parser *p)
             &&
             (bitwise_or_var = bitwise_or_rule(p))  // bitwise_or
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_162_rule, p)
+            _PyPegen_lookahead(0, _tmp_162_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' 
| 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')"));
@@ -21567,7 +21567,7 @@ invalid_default_rule(Parser *p)
         if (
             (a = _PyPegen_expect_token(p, 22))  // token='='
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_179_rule, p)
+            _PyPegen_lookahead(1, _tmp_179_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "'=' &(')' | ',')"));
@@ -22516,7 +22516,7 @@ invalid_with_item_rule(Parser *p)
             &&
             (a = expression_rule(p))  // expression
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_203_rule, p)
+            _PyPegen_lookahead(1, _tmp_203_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' 
| ')' | ':')"));
@@ -23095,7 +23095,7 @@ invalid_try_stmt_rule(Parser *p)
             &&
             (block_var = block_rule(p))  // block
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_214_rule, p)
+            _PyPegen_lookahead(0, _tmp_214_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')"));
@@ -23813,7 +23813,7 @@ invalid_as_pattern_rule(Parser *p)
             &&
             (_keyword = _PyPegen_expect_token(p, 658))  // token='as'
             &&
-            _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p)
+            _PyPegen_lookahead_for_expr(0, _PyPegen_name_token, p)
             &&
             (a = expression_rule(p))  // expression
         )
@@ -24676,7 +24676,7 @@ invalid_double_starred_kvpairs_rule(Parser *p)
             &&
             (a = _PyPegen_expect_token(p, 11))  // token=':'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_233_rule, p)
+            _PyPegen_lookahead(1, _tmp_233_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')"));
@@ -24786,7 +24786,7 @@ invalid_kvpair_rule(Parser *p)
             &&
             (a = _PyPegen_expect_token(p, 11))  // token=':'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_234_rule, p)
+            _PyPegen_lookahead(1, _tmp_234_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", 
p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')"));
@@ -25002,7 +25002,7 @@ invalid_replacement_field_rule(Parser *p)
         if (
             (_literal = _PyPegen_expect_token(p, 25))  // token='{'
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) annotated_rhs_rule, p)
+            _PyPegen_lookahead_for_expr(0, annotated_rhs_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !annotated_rhs"));
@@ -25031,7 +25031,7 @@ invalid_replacement_field_rule(Parser *p)
             &&
             (annotated_rhs_var = annotated_rhs_rule(p))  // annotated_rhs
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_235_rule, p)
+            _PyPegen_lookahead(0, _tmp_235_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | 
':' | '}')"));
@@ -25063,7 +25063,7 @@ invalid_replacement_field_rule(Parser *p)
             &&
             (_literal_1 = _PyPegen_expect_token(p, 22))  // token='='
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_236_rule, p)
+            _PyPegen_lookahead(0, _tmp_236_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | 
':' | '}')"));
@@ -25129,7 +25129,7 @@ invalid_replacement_field_rule(Parser *p)
             &&
             (_opt_var_1 = _tmp_237_rule(p), !p->error_indicator)  // ['!' NAME]
             &&
-            _PyPegen_lookahead(0, (void *(*)(Parser *)) _tmp_238_rule, p)
+            _PyPegen_lookahead(0, _tmp_238_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' 
NAME] !(':' | '}')"));
@@ -25254,7 +25254,7 @@ invalid_conversion_character_rule(Parser *p)
         if (
             (_literal = _PyPegen_expect_token(p, 54))  // token='!'
             &&
-            _PyPegen_lookahead(1, (void *(*)(Parser *)) _tmp_242_rule, p)
+            _PyPegen_lookahead(1, _tmp_242_rule, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')"));
@@ -25280,7 +25280,7 @@ invalid_conversion_character_rule(Parser *p)
         if (
             (_literal = _PyPegen_expect_token(p, 54))  // token='!'
             &&
-            _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p)
+            _PyPegen_lookahead_for_expr(0, _PyPegen_name_token, p)
         )
         {
             D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s 
succeeded!\n", p->level, ' ', _mark, p->mark, "'!' !NAME"));
diff --git a/Parser/pegen.c b/Parser/pegen.c
index d167397919f56e..656c42b348a96b 100644
--- a/Parser/pegen.c
+++ b/Parser/pegen.c
@@ -376,41 +376,34 @@ _PyPegen_is_memoized(Parser *p, int type, void *pres)
     return 0;
 }
 
-int
-_PyPegen_lookahead_with_name(int positive, expr_ty (func)(Parser *), Parser *p)
-{
-    int mark = p->mark;
-    void *res = func(p);
-    p->mark = mark;
-    return (res != NULL) == positive;
-}
-
-int
-_PyPegen_lookahead_with_string(int positive, expr_ty (func)(Parser *, const 
char*), Parser *p, const char* arg)
-{
-    int mark = p->mark;
-    void *res = func(p, arg);
-    p->mark = mark;
-    return (res != NULL) == positive;
-}
-
-int
-_PyPegen_lookahead_with_int(int positive, Token *(func)(Parser *, int), Parser 
*p, int arg)
-{
-    int mark = p->mark;
-    void *res = func(p, arg);
-    p->mark = mark;
-    return (res != NULL) == positive;
-}
-
-int
-_PyPegen_lookahead(int positive, void *(func)(Parser *), Parser *p)
-{
-    int mark = p->mark;
-    void *res = (void*)func(p);
-    p->mark = mark;
-    return (res != NULL) == positive;
-}
+#define LOOKAHEAD1(NAME, RES_TYPE)                                  \
+    int                                                             \
+    NAME (int positive, RES_TYPE (func)(Parser *), Parser *p)       \
+    {                                                               \
+        int mark = p->mark;                                         \
+        void *res = func(p);                                        \
+        p->mark = mark;                                             \
+        return (res != NULL) == positive;                           \
+    }
+
+LOOKAHEAD1(_PyPegen_lookahead, void *)
+LOOKAHEAD1(_PyPegen_lookahead_for_expr, expr_ty)
+LOOKAHEAD1(_PyPegen_lookahead_for_stmt, stmt_ty)
+#undef LOOKAHEAD1
+
+#define LOOKAHEAD2(NAME, RES_TYPE, T)                                   \
+    int                                                                 \
+    NAME (int positive, RES_TYPE (func)(Parser *, T), Parser *p, T arg) \
+    {                                                                   \
+        int mark = p->mark;                                             \
+        void *res = func(p, arg);                                       \
+        p->mark = mark;                                                 \
+        return (res != NULL) == positive;                               \
+    }
+
+LOOKAHEAD2(_PyPegen_lookahead_with_int, Token *, int)
+LOOKAHEAD2(_PyPegen_lookahead_with_string, expr_ty, const char *)
+#undef LOOKAHEAD2
 
 Token *
 _PyPegen_expect_token(Parser *p, int type)
diff --git a/Parser/pegen.h b/Parser/pegen.h
index 651659ac6c926b..1acfbae861fec3 100644
--- a/Parser/pegen.h
+++ b/Parser/pegen.h
@@ -132,10 +132,11 @@ int _PyPegen_insert_memo(Parser *p, int mark, int type, 
void *node);
 int _PyPegen_update_memo(Parser *p, int mark, int type, void *node);
 int _PyPegen_is_memoized(Parser *p, int type, void *pres);
 
-int _PyPegen_lookahead_with_name(int, expr_ty (func)(Parser *), Parser *);
-int _PyPegen_lookahead_with_int(int, Token *(func)(Parser *, int), Parser *, 
int);
-int _PyPegen_lookahead_with_string(int , expr_ty (func)(Parser *, const 
char*), Parser *, const char*);
 int _PyPegen_lookahead(int, void *(func)(Parser *), Parser *);
+int _PyPegen_lookahead_for_expr(int, expr_ty (func)(Parser *), Parser *);
+int _PyPegen_lookahead_for_stmt(int, stmt_ty (func)(Parser *), Parser *);
+int _PyPegen_lookahead_with_int(int, Token *(func)(Parser *, int), Parser *, 
int);
+int _PyPegen_lookahead_with_string(int, expr_ty (func)(Parser *, const char*), 
Parser *, const char*);
 
 Token *_PyPegen_expect_token(Parser *p, int type);
 void* _PyPegen_expect_forced_result(Parser *p, void* result, const char* 
expected);
diff --git a/Tools/peg_generator/pegen/c_generator.py 
b/Tools/peg_generator/pegen/c_generator.py
index 84ed183c762e40..c05a5110bad3e4 100644
--- a/Tools/peg_generator/pegen/c_generator.py
+++ b/Tools/peg_generator/pegen/c_generator.py
@@ -229,33 +229,47 @@ def visit_NamedItem(self, node: NamedItem) -> 
FunctionCall:
             call.assigned_variable_type = node.type
         return call
 
+    def assert_no_undefined_behavior(
+        self, call: FunctionCall, wrapper: str, expected_rtype: str | None,
+    ) -> None:
+        if call.return_type != expected_rtype:
+            raise RuntimeError(
+                f"{call.function} return type is incompatible with {wrapper}: "
+                f"expect: {expected_rtype}, actual: {call.return_type}"
+            )
+
     def lookahead_call_helper(self, node: Lookahead, positive: int) -> 
FunctionCall:
         call = self.generate_call(node.node)
-        if call.nodetype == NodeTypes.NAME_TOKEN:
-            return FunctionCall(
-                function=f"_PyPegen_lookahead_with_name",
-                arguments=[positive, call.function, *call.arguments],
-                return_type="int",
-            )
+        comment = None
+        if call.nodetype is NodeTypes.NAME_TOKEN:
+            function = "_PyPegen_lookahead_for_expr"
+            self.assert_no_undefined_behavior(call, function, "expr_ty")
+        elif call.nodetype is NodeTypes.STRING_TOKEN:
+            # _PyPegen_string_token() returns 'void *' instead of 'Token *';
+            # in addition, the overall function call would return 'expr_ty'.
+            assert call.function == "_PyPegen_string_token"
+            function = "_PyPegen_lookahead"
+            self.assert_no_undefined_behavior(call, function, "expr_ty")
         elif call.nodetype == NodeTypes.SOFT_KEYWORD:
-            return FunctionCall(
-                function=f"_PyPegen_lookahead_with_string",
-                arguments=[positive, call.function, *call.arguments],
-                return_type="int",
-            )
+            function = "_PyPegen_lookahead_with_string"
+            self.assert_no_undefined_behavior(call, function, "expr_ty")
         elif call.nodetype in {NodeTypes.GENERIC_TOKEN, NodeTypes.KEYWORD}:
-            return FunctionCall(
-                function=f"_PyPegen_lookahead_with_int",
-                arguments=[positive, call.function, *call.arguments],
-                return_type="int",
-                comment=f"token={node.node}",
-            )
+            function = "_PyPegen_lookahead_with_int"
+            self.assert_no_undefined_behavior(call, function, "Token *")
+            comment = f"token={node.node}"
+        elif call.return_type == "expr_ty":
+            function = "_PyPegen_lookahead_for_expr"
+        elif call.return_type == "stmt_ty":
+            function = "_PyPegen_lookahead_for_stmt"
         else:
-            return FunctionCall(
-                function=f"_PyPegen_lookahead",
-                arguments=[positive, f"(void *(*)(Parser *)) {call.function}", 
*call.arguments],
-                return_type="int",
-            )
+            function = "_PyPegen_lookahead"
+            self.assert_no_undefined_behavior(call, function, None)
+        return FunctionCall(
+            function=function,
+            arguments=[positive, call.function, *call.arguments],
+            return_type="int",
+            comment=comment,
+        )
 
     def visit_PositiveLookahead(self, node: PositiveLookahead) -> FunctionCall:
         return self.lookahead_call_helper(node, 1)

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to