@@ -906,25 +906,36 @@ void ast_pp(DemNode *node, DemString *out, PPContext *ctx) {
906906 }
907907 break ;
908908
909- case CP_DEM_TYPE_KIND_CLOSURE_TY_NAME :
910- // Closure types are lambda expressions: 'lambda'(params)#count
909+ case CP_DEM_TYPE_KIND_CLOSURE_TY_NAME : {
910+ // Closure types are lambda expressions: 'lambda[count]'<template_params> [ requires expr ] (params) [ requires expr ]
911+ const ClosureTyName * ctn = & node -> closure_ty_name ;
911912 dem_string_append (out , "'lambda" );
912- if (node -> closure_ty_name .template_params && node -> closure_ty_name .template_params -> children ) {
913+ if (ctn -> count .buf && ctn -> count .len > 0 ) {
914+ dem_string_append_sv (out , ctn -> count );
915+ }
916+ dem_string_append (out , "'" );
917+
918+ if (ctn -> template_params && ctn -> template_params -> children ) {
913919 dem_string_append (out , "<" );
914920 ast_pp (node -> closure_ty_name .template_params , out , ctx );
915921 dem_string_append (out , ">" );
916922 }
917- dem_string_append (out , "'(" );
923+ if (ctn -> requires1 ) {
924+ dem_string_append (out , " requires " );
925+ ast_pp (ctn -> requires1 , out , ctx );
926+ }
927+
928+ print_open (out , ctx );
918929 if (node -> closure_ty_name .params ) {
919930 ast_pp (node -> closure_ty_name .params , out , ctx );
920931 }
921- dem_string_append (out , ")" );
922- if (node -> closure_ty_name . count . buf && node -> closure_ty_name . count . len > 0 ) {
923- dem_string_append (out , "# " );
924- dem_string_append_n ( out , node -> closure_ty_name . count . buf , node -> closure_ty_name . count . len );
932+ print_close (out , ctx );
933+ if (ctn -> requires2 ) {
934+ dem_string_append (out , " requires " );
935+ ast_pp ( ctn -> requires2 , out , ctx );
925936 }
926937 break ;
927-
938+ }
928939 case CP_DEM_TYPE_KIND_TYPE : {
929940 // Check if this is a function pointer (or pointer/reference/qualified wrapping a function pointer)
930941 DemNode * func_node = NULL ;
@@ -3187,7 +3198,7 @@ bool rule_template_arg(DemParser *p, DemResult *r) {
31873198 if (!is_template_param_decl (p )) {
31883199 RETURN_SUCCESS_OR_FAIL (CALL_RULE_REPLACE_NODE (rule_type ));
31893200 }
3190- DEM_UNREACHABLE ;
3201+ RETURN_SUCCESS_OR_FAIL ( CALL_RULE_REPLACE_NODE ( rule_template_param_decl )) ;
31913202 }
31923203 default :
31933204 RETURN_SUCCESS_OR_FAIL (CALL_RULE_REPLACE_NODE (rule_type ));
@@ -3238,7 +3249,14 @@ bool rule_template_args_ex(DemParser *p, DemResult *r, bool tag_templates) {
32383249 }
32393250 Node_append (many_node , arg );
32403251 if (READ ('Q' )) {
3241- DEM_UNREACHABLE ;
3252+ // C++20 constraint expression attached to the template argument.
3253+ // Minimal support: parse it as an expression and ignore it.
3254+ // (Pretty-printing a per-argument constraint isn't currently supported.)
3255+ PDemNode constraint_expr = NULL ;
3256+ if (!(CALL_RULE_N (constraint_expr , rule_expression ) && READ ('E' ))) {
3257+ TRACE_RETURN_FAILURE ();
3258+ }
3259+ DemNode_dtor (constraint_expr );
32423260 }
32433261 }
32443262 many_node -> many_ty .sep = ", " ;
@@ -3320,21 +3338,35 @@ bool rule_unnamed_type_name(DemParser *p, DemResult *r) {
33203338 TRACE_RETURN_SUCCESS ;
33213339 }
33223340 if (READ_STR ("Ul" )) {
3323- while (is_template_param_decl (p )) {
3324- // TODO: Handle template_param_decl
3325- DEM_UNREACHABLE ;
3341+ // Ul <template-param-decl>* [Q <constraint-expr> E] <lambda-sig> [Q <constraint-expr> E] E <number> _
3342+ PDemNode template_params = NULL ;
3343+ if (is_template_param_decl (p )) {
3344+ if (!CALL_MANY1_N (template_params , rule_template_param_decl , ", " , '\0' )) {
3345+ TRACE_RETURN_FAILURE ();
3346+ }
3347+ }
3348+ if (template_params && VecPDemNode_empty (template_params -> children )) {
3349+ VecPNodeList_pop (& p -> template_params );
33263350 }
3351+
3352+ PDemNode requires1 = NULL ;
33273353 if (READ ('Q' )) {
3328- // TODO: Handle ConstraintExpr
3329- DEM_UNREACHABLE ;
3354+ // C++20 constraint expression (templated lambda) - minimal support: parse & ignore.
3355+ MUST_MATCH (CALL_RULE_N (requires1 , rule_expression ) && READ ('E' ));
3356+ if (!requires1 ) {
3357+ TRACE_RETURN_FAILURE ();
3358+ }
33303359 }
33313360 DemNode * params = NULL ;
33323361 if (!READ ('v' )) {
3333- CALL_MANY1_N (params , rule_type , ", " , 'E ' );
3362+ CALL_MANY1_N (params , rule_type , ", " , '\0 ' );
33343363 }
3364+ PDemNode requires2 = NULL ;
33353365 if (READ ('Q' )) {
3336- // TODO: Handle ConstraintExpr
3337- DEM_UNREACHABLE ;
3366+ MUST_MATCH (CALL_RULE_N (requires2 , rule_expression ) && READ ('E' ));
3367+ if (!requires2 ) {
3368+ TRACE_RETURN_FAILURE ();
3369+ }
33383370 }
33393371 if (!READ ('E' )) {
33403372 TRACE_RETURN_FAILURE ();
@@ -3346,7 +3378,10 @@ bool rule_unnamed_type_name(DemParser *p, DemResult *r) {
33463378 TRACE_RETURN_FAILURE ();
33473379 }
33483380 node -> tag = CP_DEM_TYPE_KIND_CLOSURE_TY_NAME ;
3381+ node -> closure_ty_name .template_params = template_params ;
33493382 node -> closure_ty_name .params = params ;
3383+ node -> closure_ty_name .requires1 = requires1 ;
3384+ node -> closure_ty_name .requires2 = requires2 ;
33503385 TRACE_RETURN_SUCCESS ;
33513386 }
33523387 RULE_FOOT (unnamed_type_name );
0 commit comments