* init.c (get_nsdmi): Remember NSDMI instantiations.
* parser.c (inject_this_parameter): Be more picky about
current_class_ptr.
* pt.c (tsubst_copy): Simplify 'this' handling.
(tsubst_default_argument): Remember default argument
instantiations. Take parameter number.
(tsubst_default_arguments): Pass it.
* call.c (convert_default_arg): Likewise.
From-SVN: r251422
2017-08-29 Jason Merrill <jason@redhat.com>
+ Instantiate default arguments/member initializers once.
+ * init.c (get_nsdmi): Remember NSDMI instantiations.
+ * parser.c (inject_this_parameter): Be more picky about
+ current_class_ptr.
+ * pt.c (tsubst_copy): Simplify 'this' handling.
+ (tsubst_default_argument): Remember default argument
+ instantiations. Take parameter number.
+ (tsubst_default_arguments): Pass it.
+ * call.c (convert_default_arg): Likewise.
+
Fix default argument conversion failure and SFINAE.
* call.c (build_over_call): Check convert_default_arg result for
error_mark_node.
push_defarg_context (fn);
if (fn && DECL_TEMPLATE_INFO (fn))
- arg = tsubst_default_argument (fn, type, arg, complain);
+ arg = tsubst_default_argument (fn, parmnum, type, arg, complain);
/* Due to:
extern tree most_specialized_instantiation (tree);
extern void print_candidates (tree);
extern void instantiate_pending_templates (int);
-extern tree tsubst_default_argument (tree, tree, tree,
+extern tree tsubst_default_argument (tree, int, tree, tree,
tsubst_flags_t);
extern tree tsubst (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
/* Return the non-static data initializer for FIELD_DECL MEMBER. */
+static GTY(()) hash_map<tree, tree> *nsdmi_inst;
+
tree
get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
{
tree save_ccp = current_class_ptr;
tree save_ccr = current_class_ref;
- if (!in_ctor)
- {
- /* Use a PLACEHOLDER_EXPR when we don't have a 'this' parameter to
- refer to; constexpr evaluation knows what to do with it. */
- current_class_ref = build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (member));
- current_class_ptr = build_address (current_class_ref);
- }
-
if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
{
init = DECL_INITIAL (DECL_TI_TEMPLATE (member));
+ location_t expr_loc
+ = EXPR_LOC_OR_LOC (init, DECL_SOURCE_LOCATION (member));
+ tree *slot;
if (TREE_CODE (init) == DEFAULT_ARG)
/* Unparsed. */;
+ else if (nsdmi_inst && (slot = nsdmi_inst->get (member)))
+ init = *slot;
/* Check recursive instantiation. */
else if (DECL_INSTANTIATING_NSDMI_P (member))
{
if (complain & tf_error)
- error ("recursive instantiation of default member "
- "initializer for %qD", member);
+ error_at (expr_loc, "recursive instantiation of default member "
+ "initializer for %qD", member);
init = error_mark_node;
}
else
{
+ int un = cp_unevaluated_operand;
+ cp_unevaluated_operand = 0;
+
+ location_t sloc = input_location;
+ input_location = expr_loc;
+
DECL_INSTANTIATING_NSDMI_P (member) = 1;
+ inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
+
/* Do deferred instantiation of the NSDMI. */
init = (tsubst_copy_and_build
(init, DECL_TI_ARGS (member),
init = digest_nsdmi_init (member, init, complain);
DECL_INSTANTIATING_NSDMI_P (member) = 0;
+
+ if (init != error_mark_node)
+ {
+ if (!nsdmi_inst)
+ nsdmi_inst = hash_map<tree,tree>::create_ggc (37);
+ nsdmi_inst->put (member, init);
+ }
+
+ input_location = sloc;
+ cp_unevaluated_operand = un;
}
}
else
init = error_mark_node;
}
+ if (in_ctor)
+ {
+ current_class_ptr = save_ccp;
+ current_class_ref = save_ccr;
+ }
+ else
+ {
+ /* Use a PLACEHOLDER_EXPR when we don't have a 'this' parameter to
+ refer to; constexpr evaluation knows what to do with it. */
+ current_class_ref = build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (member));
+ current_class_ptr = build_address (current_class_ref);
+ }
+
/* Strip redundant TARGET_EXPR so we don't need to remap it, and
so the aggregate init code below will see a CONSTRUCTOR. */
bool simple_target = (init && SIMPLE_TARGET_EXPR_P (init));
{
/* We don't clear this between NSDMIs. Is it already what we want? */
tree type = TREE_TYPE (TREE_TYPE (current_class_ptr));
- if (same_type_ignoring_top_level_qualifiers_p (ctype, type)
+ if (DECL_P (current_class_ptr)
+ && DECL_CONTEXT (current_class_ptr) == NULL_TREE
+ && same_type_ignoring_top_level_qualifiers_p (ctype, type)
&& cp_type_quals (type) == quals)
return;
}
}
}
+static GTY(()) hash_map<tree, tree> *defarg_inst;
+
/* Substitute into the default argument ARG (a default argument for
FN), which has the indicated TYPE. */
tree
-tsubst_default_argument (tree fn, tree type, tree arg, tsubst_flags_t complain)
+tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
+ tsubst_flags_t complain)
{
tree saved_class_ptr = NULL_TREE;
tree saved_class_ref = NULL_TREE;
if (TREE_CODE (arg) == DEFAULT_ARG)
return arg;
+ tree parm = FUNCTION_FIRST_USER_PARM (fn);
+ parm = chain_index (parmnum, parm);
+ tree parmtype = TREE_TYPE (parm);
+ if (DECL_BY_REFERENCE (parm))
+ parmtype = TREE_TYPE (parmtype);
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, parmtype));
+
+ tree *slot;
+ if (defarg_inst && (slot = defarg_inst->get (parm)))
+ return *slot;
+
/* This default argument came from a template. Instantiate the
default argument here, not in tsubst. In the case of
something like:
pop_access_scope (fn);
+ if (arg != error_mark_node && !cp_unevaluated_operand)
+ {
+ if (!defarg_inst)
+ defarg_inst = hash_map<tree,tree>::create_ggc (37);
+ defarg_inst->put (parm, arg);
+ }
+
return arg;
}
if (DECL_CLONED_FUNCTION_P (fn))
return;
+ int i = 0;
for (arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
arg;
- arg = TREE_CHAIN (arg))
+ arg = TREE_CHAIN (arg), ++i)
if (TREE_PURPOSE (arg))
- TREE_PURPOSE (arg) = tsubst_default_argument (fn,
+ TREE_PURPOSE (arg) = tsubst_default_argument (fn, i,
TREE_VALUE (arg),
TREE_PURPOSE (arg),
complain);
if (r == NULL_TREE)
{
- /* We get here for a use of 'this' in an NSDMI as part of a
- constructor call or as part of an aggregate initialization. */
- if (DECL_NAME (t) == this_identifier
- && ((current_function_decl
- && DECL_CONSTRUCTOR_P (current_function_decl))
- || (current_class_ref
- && TREE_CODE (current_class_ref) == PLACEHOLDER_EXPR)))
+ /* We get here for a use of 'this' in an NSDMI. */
+ if (DECL_NAME (t) == this_identifier && current_class_ptr)
return current_class_ptr;
/* This can happen for a parameter name used later in a function
// PR c++/62155
// { dg-do compile { target c++11 } }
-template <typename T> struct S { // { dg-error "cannot convert" }
- T i{[this] {}};
+template <typename T> struct S {
+ T i{[this] {}}; // { dg-error "cannot convert" }
};
-S<int> s; // { dg-error "cannot convert" }
+S<int> s; // { dg-message "required" }
template <int N>
struct W2
{
- A a { 5 }; // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
- B b { 6 }; // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
- C c { 3.0f }; // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
- // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
- D d = { 7 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+ A a { 5 }; // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } }
+ B b { 6 }; // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+ C c { 3.0f }; // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } }
+ // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-1 }
+ D d = { 7 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } }
};
template <typename H, typename I, typename J, typename K, typename L, typename M>
template <typename H, typename I, typename J, typename K>
struct W3
{
- H a { 5 }; // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
- I b { 6 }; // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
- J c { 3.0f }; // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
- // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
- K d = { 7 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+ H a { 5 }; // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } }
+ I b { 6 }; // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+ J c { 3.0f }; // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } }
+ // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-1 }
+ K d = { 7 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } }
};
void
foo2<0> ();
U2<0> u20;
U2<1> u21 (5);
- W2<0> w2; // { dg-error "invalid conversion from 'int' to 'A'" }
- // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
- // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
- // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
- // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+ W2<0> w2; // { dg-message "" }
foo3<A, B, C, D, E, V> ();
U3<E> u30;
U3<E> u31 (5);
- W3<A, B, C, D> w3; // { dg-error "invalid conversion from 'int' to 'A'" }
- // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
- // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
- // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
- // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+ W3<A, B, C, D> w3; // { dg-message "" }
}