return maybe_wrap_with_location (op0, EXPR_LOCATION (t));
}
tree op = TREE_OPERAND (t, 0);
- if (code == VIEW_CONVERT_EXPR
- && TREE_CODE (op) == TEMPLATE_PARM_INDEX)
- {
- /* Wrapper to make a C++20 template parameter object const. */
- op = tsubst_copy (op, args, complain, in_decl);
- if (!CP_TYPE_CONST_P (TREE_TYPE (op)))
- {
- /* The template argument is not const, presumably because
- it is still dependent, and so not the const template parm
- object. */
- tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
- (type, TREE_TYPE (op)));
- if (TREE_CODE (op) == CONSTRUCTOR
- || TREE_CODE (op) == IMPLICIT_CONV_EXPR)
- {
- /* Don't add a wrapper to these. */
- op = copy_node (op);
- TREE_TYPE (op) = type;
- }
- else
- /* Do add a wrapper otherwise (in particular, if op is
- another TEMPLATE_PARM_INDEX). */
- op = build1 (code, type, op);
- }
- return op;
- }
/* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
- else if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t))
+ if (code == VIEW_CONVERT_EXPR && REF_PARENTHESIZED_P (t))
{
op = tsubst_copy (op, args, complain, in_decl);
op = build1 (code, TREE_TYPE (op), op);
REF_PARENTHESIZED_P (op) = true;
return op;
}
- /* We shouldn't see any other uses of these in templates. */
+ /* We shouldn't see any other uses of these in templates
+ (tsubst_copy_and_build handles C++20 tparm object wrappers). */
gcc_unreachable ();
}
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
- if (location_wrapper_p (t))
- /* We need to do this here as well as in tsubst_copy so we get the
- other tsubst_copy_and_build semantics for a PARM_DECL operand. */
- RETURN (maybe_wrap_with_location (RECUR (TREE_OPERAND (t, 0)),
- EXPR_LOCATION (t)));
- /* fallthrough. */
+ {
+ tree op = RECUR (TREE_OPERAND (t, 0));
+
+ if (location_wrapper_p (t))
+ /* We need to do this here as well as in tsubst_copy so we get the
+ other tsubst_copy_and_build semantics for a PARM_DECL operand. */
+ RETURN (maybe_wrap_with_location (op, EXPR_LOCATION (t)));
+
+ gcc_checking_assert (TREE_CODE (t) == VIEW_CONVERT_EXPR);
+ if (REF_PARENTHESIZED_P (t))
+ /* force_paren_expr can also create a VIEW_CONVERT_EXPR. */
+ RETURN (finish_parenthesized_expr (op));
+
+ /* Otherwise, we're dealing with a wrapper to make a C++20 template
+ parameter object const. */
+ if (TREE_TYPE (op) == NULL_TREE
+ || !CP_TYPE_CONST_P (TREE_TYPE (op)))
+ {
+ /* The template argument is not const, presumably because
+ it is still dependent, and so not the const template parm
+ object. */
+ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ if (TREE_CODE (op) == CONSTRUCTOR
+ || TREE_CODE (op) == IMPLICIT_CONV_EXPR)
+ {
+ /* Don't add a wrapper to these. */
+ op = copy_node (op);
+ TREE_TYPE (op) = type;
+ }
+ else
+ /* Do add a wrapper otherwise (in particular, if op is
+ another TEMPLATE_PARM_INDEX). */
+ op = build1 (VIEW_CONVERT_EXPR, type, op);
+ }
+ RETURN (op);
+ }
default:
/* Handle Objective-C++ constructs, if appropriate. */
--- /dev/null
+// PR c++/103346
+// { dg-do compile { target c++20 } }
+
+struct Item {};
+
+template<class T, T... ts>
+struct Sequence { };
+
+template<Item... items>
+using ItemSequence = Sequence<Item, items...>;
+
+template<Item... items>
+constexpr auto f() {
+ constexpr auto l = [](Item item) { return item; };
+ return ItemSequence<l(items)...>{};
+}
+
+using ty0 = decltype(f<>());
+using ty0 = ItemSequence<>;
+
+using ty1 = decltype(f<{}>());
+using ty1 = ItemSequence<{}>;
+
+using ty3 = decltype(f<{}, {}, {}>());
+using ty3 = ItemSequence<{}, {}, {}>;