@@ -73,6 +73,9 @@ static a_boolean is_unmodifiable_initonly_field_operand(
7373static void mark_init_component_as_permanently_allocated(
7474 an_init_component *icp);
7575static void prep_generic_init_component_list(an_arg_list_elem_ptr list);
76+ static void make_template_param_object_operand(a_constant_ptr cp,
77+ an_operand *operand,
78+ a_boolean copy_constant);
7679
7780
7881/*
@@ -4913,6 +4916,7 @@ in *bound_function_selector.
49134916 an_expr_node_ptr orig_expr = expr;
49144917 an_expr_node_ptr expr_copy = NULL;
49154918 a_boolean rescanned_case = FALSE;
4919+ a_boolean is_template_param_object = FALSE;
49164920 a_constant_ptr constant = local_constant();
49174921 a_constant_ptr alloc_con = NULL;
49184922 an_expr_rescan_info_entry_ptr eriep;
@@ -4964,11 +4968,35 @@ in *bound_function_selector.
49644968 /* The operand was already built above. */
49654969 } else {
49664970 if (expr_copy == NULL) {
4967- /* The result is a constant, so return a constant operand. */
4968- if (alloc_con != NULL) {
4969- make_constant_operand(alloc_con, operand);
4971+ a_constant_ptr cp = alloc_con != NULL ? alloc_con : constant;
4972+ if (is_constant_node(expr) &&
4973+ constant_is(node_constant(expr), ck_template_param) &&
4974+ tpck_is(node_constant(expr), tpck_param) &&
4975+ constant_is(cp, ck_aggregate)) {
4976+ /* A C++20 nontype template parameter of class type has been
4977+ replaced by its argument value. As when such a parameter is
4978+ referenced in an instantiation (see make_sym_constant_operand),
4979+ the result is an lvalue designating the template parameter
4980+ object. That object is identified by the argument value
4981+ itself, i.e., without the "const" that substitution adds to
4982+ the value. */
4983+ if (cp != constant) {
4984+ /* cp may be the template argument itself (if the argument value
4985+ was produced by an earlier substitution), so it must not be
4986+ modified. */
4987+ copy_constant(cp, constant);
4988+ cp = constant;
4989+ } /* if */
4990+ if (cp->variant.aggregate.added_const_for_template_param) {
4991+ cp->type = remove_qualifiers(cp->type, TQ_CONST);
4992+ cp->variant.aggregate.added_const_for_template_param = FALSE;
4993+ } /* if */
4994+ make_template_param_object_operand(cp, operand,
4995+ /*copy_constant=*/TRUE);
4996+ is_template_param_object = TRUE;
49704997 } else {
4971- make_constant_operand(constant, operand);
4998+ /* The result is a constant, so return a constant operand. */
4999+ make_constant_operand(cp, operand);
49725000 } /* if */
49735001 } else {
49745002 /* Return an expression operand. */
@@ -4992,6 +5020,15 @@ in *bound_function_selector.
49925020 /* Normal case: restore everything. */
49935021 restore_operand_info_from_expr_rescan_info_entry(operand, eriep);
49945022 } /* if */
5023+ if (is_template_param_object && orig_expr->extra.rescan_info != NULL) {
5024+ /* The rescan information on the template parameter constant was
5025+ saved before the reference was identified as an id-expression
5026+ (possibly parenthesized). That is recorded on the node that makes
5027+ the reference an lvalue (see make_sym_constant_operand), and it
5028+ matters, e.g., for decltype. */
5029+ restore_operand_id_details(operand,
5030+ &orig_expr->extra.rescan_info->saved_operand);
5031+ } /* if */
49955032 } /* if */
49965033 release_local_constant(&constant);
49975034} /* make_rescan_operand_full */
@@ -8467,11 +8504,15 @@ STATIC_THREAD a_template_param_object_map
84678504 object. */
84688505
84698506static void make_template_param_object_operand(a_constant_ptr cp,
8470- an_operand *operand)
8507+ an_operand *operand,
8508+ a_boolean copy_constant)
84718509/*
84728510Make operand an lvalue expression operand for the template parameter object
84738511associated with the constant cp. If needed, create that object (as a variable
8474- entry).
8512+ entry). copy_constant is TRUE if cp is a local constant (rather than an
8513+ allocated IL constant): If the object is created, its value is then a copy of
8514+ cp, including its subconstants (which may be shared with other constants),
8515+ allocated in the file scope memory region.
84758516*/
84768517{
84778518 a_constant_handle ch = { cp };
@@ -8480,6 +8521,15 @@ entry).
84808521 if (vp == NULL) {
84818522 a_symbol_ptr sym = make_template_param_object_sym(&error_position);
84828523 a_type_ptr vtp = cp->type;
8524+ if (copy_constant) {
8525+ a_memory_region_number region_to_switch_back_to;
8526+ switch_to_file_scope_region(®ion_to_switch_back_to);
8527+ cp = copy_constant_full(cp, (a_constant *)NULL,
8528+ CE_SRC_CONSTANT_IS_NOT_ALLOC_IN_IL);
8529+ switch_back_to_original_region(region_to_switch_back_to);
8530+ break_constant_source_corresp(cp);
8531+ ch.ptr = cp;
8532+ } /* if */
84838533 vp = make_variable(vtp, sc_unspecified, DEPTH_OF_FILE_SCOPE);
84848534 vp->is_template_param_object = TRUE;
84858535 vp->is_constexpr = TRUE;
@@ -8541,7 +8591,8 @@ The position of the current token will be used as the operand position.
85418591 /* A C++20 nontype template parameter instantiated with a class type
85428592 constant. Create a variable operand referring to the underlying
85438593 template parameter object. */
8544- make_template_param_object_operand(con_ptr, operand);
8594+ make_template_param_object_operand(con_ptr, operand,
8595+ /*copy_constant=*/FALSE);
85458596 } else {
85468597 /* Normal (non-reference) case. */
85478598 make_constant_operand(&constant, operand);
0 commit comments