return unify_invalid (explain_p);
}
+/* True if T is a C++20 template parameter object to store the argument for a
+ template parameter of class type. */
+
+bool
+template_parm_object_p (const_tree t)
+{
+ return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t) && DECL_NAME (t)
+ && !strncmp (IDENTIFIER_POINTER (DECL_NAME (t)), "_ZTA", 4));
+}
+
+/* Subroutine of convert_nontype_argument, to check whether EXPR, as an
+ argument for TYPE, points to an unsuitable object. */
+
+static bool
+invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
+{
+ switch (TREE_CODE (expr))
+ {
+ CASE_CONVERT:
+ return invalid_tparm_referent_p (type, TREE_OPERAND (expr, 0),
+ complain);
+
+ case TARGET_EXPR:
+ return invalid_tparm_referent_p (type, TARGET_EXPR_INITIAL (expr),
+ complain);
+
+ case CONSTRUCTOR:
+ {
+ unsigned i; tree elt;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, elt)
+ if (invalid_tparm_referent_p (TREE_TYPE (elt), elt, complain))
+ return true;
+ }
+ break;
+
+ case ADDR_EXPR:
+ {
+ tree decl = TREE_OPERAND (expr, 0);
+
+ if (!VAR_P (decl))
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument of type %qT "
+ "because %qE is not a variable", expr, type, decl);
+ return true;
+ }
+ else if (cxx_dialect < cxx11 && !DECL_EXTERNAL_LINKAGE_P (decl))
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument of type %qT "
+ "in C++98 because %qD does not have external linkage",
+ expr, type, decl);
+ return true;
+ }
+ else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx17)
+ && decl_linkage (decl) == lk_none)
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument of type %qT "
+ "because %qD has no linkage", expr, type, decl);
+ return true;
+ }
+ /* C++17: For a non-type template-parameter of reference or pointer
+ type, the value of the constant expression shall not refer to (or
+ for a pointer type, shall not be the address of):
+ * a subobject (4.5),
+ * a temporary object (15.2),
+ * a string literal (5.13.5),
+ * the result of a typeid expression (8.2.8), or
+ * a predefined __func__ variable (11.4.1). */
+ else if (DECL_ARTIFICIAL (decl))
+ {
+ if (complain & tf_error)
+ error ("the address of %qD is not a valid template argument",
+ decl);
+ return true;
+ }
+ else if (!same_type_ignoring_top_level_qualifiers_p
+ (strip_array_types (TREE_TYPE (type)),
+ strip_array_types (TREE_TYPE (decl))))
+ {
+ if (complain & tf_error)
+ error ("the address of the %qT subobject of %qD is not a "
+ "valid template argument", TREE_TYPE (type), decl);
+ return true;
+ }
+ else if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ {
+ if (complain & tf_error)
+ error ("the address of %qD is not a valid template argument "
+ "because it does not have static storage duration",
+ decl);
+ return true;
+ }
+ }
+ break;
+
+ default:
+ if (!INDIRECT_TYPE_P (type))
+ /* We're only concerned about pointers and references here. */;
+ else if (cxx_dialect >= cxx11 && integer_zerop (expr))
+ /* Null pointer values are OK in C++11. */;
+ else
+ {
+ if (VAR_P (expr))
+ {
+ if (complain & tf_error)
+ error ("%qD is not a valid template argument "
+ "because %qD is a variable, not the address of "
+ "a variable", expr, expr);
+ return true;
+ }
+ else
+ {
+ if (complain & tf_error)
+ error ("%qE is not a valid template argument for %qT "
+ "because it is not the address of a variable",
+ expr, type);
+ return true;
+ }
+ }
+ }
+ return false;
+
+}
+
+/* Return a VAR_DECL for the C++20 template parameter object corresponding to
+ template argument EXPR. */
+
+static tree
+get_template_parm_object (tree expr, tsubst_flags_t complain)
+{
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ expr = TARGET_EXPR_INITIAL (expr);
+
+ if (!TREE_CONSTANT (expr))
+ {
+ if ((complain & tf_error)
+ && require_rvalue_constant_expression (expr))
+ cxx_constant_value (expr);
+ return error_mark_node;
+ }
+ if (invalid_tparm_referent_p (TREE_TYPE (expr), expr, complain))
+ return error_mark_node;
+
+ tree name = mangle_template_parm_object (expr);
+ tree decl = get_global_binding (name);
+ if (decl)
+ return decl;
+
+ tree type = cp_build_qualified_type (TREE_TYPE (expr), TYPE_QUAL_CONST);
+ decl = create_temporary_var (type);
+ TREE_STATIC (decl) = true;
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ TREE_READONLY (decl) = true;
+ DECL_NAME (decl) = name;
+ SET_DECL_ASSEMBLER_NAME (decl, name);
+ DECL_CONTEXT (decl) = global_namespace;
+ comdat_linkage (decl);
+ pushdecl_top_level_and_finish (decl, expr);
+ return decl;
+}
+
/* Attempt to convert the non-type template parameter EXPR to the
indicated TYPE. If the conversion is successful, return the
converted value. If the conversion is unsuccessful, return
{
tree expr_type;
location_t loc = cp_expr_loc_or_loc (expr, input_location);
- tree orig_expr = expr;
/* Detect immediately string literals as invalid non-type argument.
This special-case is not needed for correctness (we would easily
catch this later), but only to provide better diagnostic for this
common user mistake. As suggested by DR 100, we do not mention
linkage issues in the diagnostic as this is not the point. */
- /* FIXME we're making this OK. */
- if (TREE_CODE (expr) == STRING_CST)
+ if (TREE_CODE (expr) == STRING_CST && !CLASS_TYPE_P (type))
{
if (complain & tf_error)
error ("%qE is not a valid template argument for type %qT "
;
else if (cxx_dialect >= cxx11 && integer_zerop (expr))
/* Null pointer values are OK in C++11. */;
- else if (TREE_CODE (expr) != ADDR_EXPR)
- {
- if (VAR_P (expr))
- {
- if (complain & tf_error)
- error ("%qD is not a valid template argument "
- "because %qD is a variable, not the address of "
- "a variable", orig_expr, expr);
- return NULL_TREE;
- }
- if (INDIRECT_TYPE_P (expr_type))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for %qT "
- "because it is not the address of a variable",
- orig_expr, type);
- return NULL_TREE;
- }
- /* Other values, like integer constants, might be valid
- non-type arguments of some other type. */
- return error_mark_node;
- }
- else
- {
- tree decl = TREE_OPERAND (expr, 0);
-
- if (!VAR_P (decl))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument of type %qT "
- "because %qE is not a variable", orig_expr, type, decl);
- return NULL_TREE;
- }
- else if (cxx_dialect < cxx11 && !DECL_EXTERNAL_LINKAGE_P (decl))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument of type %qT "
- "because %qD does not have external linkage",
- orig_expr, type, decl);
- return NULL_TREE;
- }
- else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx17)
- && decl_linkage (decl) == lk_none)
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument of type %qT "
- "because %qD has no linkage", orig_expr, type, decl);
- return NULL_TREE;
- }
- /* C++17: For a non-type template-parameter of reference or pointer
- type, the value of the constant expression shall not refer to (or
- for a pointer type, shall not be the address of):
- * a subobject (4.5),
- * a temporary object (15.2),
- * a string literal (5.13.5),
- * the result of a typeid expression (8.2.8), or
- * a predefined __func__ variable (11.4.1). */
- else if (DECL_ARTIFICIAL (decl))
- {
- if (complain & tf_error)
- error ("the address of %qD is not a valid template argument",
- decl);
- return NULL_TREE;
- }
- else if (!same_type_ignoring_top_level_qualifiers_p
- (strip_array_types (TREE_TYPE (type)),
- strip_array_types (TREE_TYPE (decl))))
- {
- if (complain & tf_error)
- error ("the address of the %qT subobject of %qD is not a "
- "valid template argument", TREE_TYPE (type), decl);
- return NULL_TREE;
- }
- else if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
- {
- if (complain & tf_error)
- error ("the address of %qD is not a valid template argument "
- "because it does not have static storage duration",
- decl);
- return NULL_TREE;
- }
- }
+ else if (TREE_CODE (expr) != ADDR_EXPR
+ && !INDIRECT_TYPE_P (expr_type))
+ /* Other values, like integer constants, might be valid
+ non-type arguments of some other type. */
+ return error_mark_node;
+ else if (invalid_tparm_referent_p (type, expr, complain))
+ return NULL_TREE;
expr = decayed;
itself value-dependent, since what we want here is its address. */;
else
{
- if (!DECL_P (expr))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for type %qT "
- "because it is not an object with linkage",
- expr, type);
- return NULL_TREE;
- }
-
- /* DR 1155 allows internal linkage in C++11 and up. */
- linkage_kind linkage = decl_linkage (expr);
- if (linkage < (cxx_dialect >= cxx11 ? lk_internal : lk_external))
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for type %qT "
- "because object %qD does not have linkage",
- expr, type, expr);
- return NULL_TREE;
- }
-
expr = build_address (expr);
+
+ if (invalid_tparm_referent_p (type, expr, complain))
+ return NULL_TREE;
}
if (!same_type_p (type, TREE_TYPE (expr)))
}
return expr;
}
+ else if (CLASS_TYPE_P (type))
+ {
+ /* Replace the argument with a reference to the corresponding template
+ parameter object. */
+ expr = get_template_parm_object (expr, complain);
+ if (expr == error_mark_node)
+ return NULL_TREE;
+ }
/* A template non-type parameter must be one of the above. */
else
gcc_unreachable ();
first, *then* reusing the resulting type. Doing the type
first ensures that we handle template parameters and
parameter pack expansions. */
- gcc_assert (location_wrapper_p (t));
- tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
- return maybe_wrap_with_location (op0, EXPR_LOCATION (t));
+ if (location_wrapper_p (t))
+ {
+ tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args,
+ complain, in_decl);
+ 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 (TREE_CODE (op) == TEMPLATE_PARM_INDEX)
+ {
+ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ return build1 (code, type, op);
+ }
+ else
+ {
+ gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (op)));
+ return op;
+ }
+ }
+ /* We shouldn't see any other uses of these in templates. */
+ gcc_unreachable ();
}
case CAST_EXPR:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
- /* We should only see these for location wrapper nodes, or within
- instantiate_non_dependent_expr (when args is NULL_TREE). */
- gcc_assert (location_wrapper_p (t) || args == NULL_TREE);
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. */
else if (cxx_dialect >= cxx11
&& TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
return false;
+ else if (CLASS_TYPE_P (type))
+ {
+ if (cxx_dialect < cxx2a)
+ {
+ error ("non-type template parameters of class type only available "
+ "with -std=c++2a or -std=gnu++2a");
+ return true;
+ }
+ if (!complete_type_or_else (type, NULL_TREE))
+ return true;
+ if (!literal_type_p (type))
+ {
+ error ("%qT is not a valid type for a template non-type parameter "
+ "because it is not literal", type);
+ explain_non_literal_class (type);
+ return true;
+ }
+ if (cp_has_mutable_p (type))
+ {
+ error ("%qT is not a valid type for a template non-type parameter "
+ "because it has a mutable member", type);
+ return true;
+ }
+ /* FIXME check op<=> and strong structural equality once spaceship is
+ implemented. */
+ return false;
+ }
if (complain & tf_error)
{
return NULL_TREE;
case TEMPLATE_PARM_INDEX:
- return *tp;
+ if (dependent_type_p (TREE_TYPE (*tp)))
+ return *tp;
+ /* We'll check value-dependence separately. */
+ return NULL_TREE;
/* Handle expressions with type operands. */
case SIZEOF_EXPR: