return false;
}
+/* Returns true iff class T has a constructor that accepts a single argument
+ and does not have a single parameter of type reference to T.
+
+ This does not exclude explicit constructors because they are still
+ considered for conversions within { } even though choosing one is
+ ill-formed. */
+
+bool
+type_has_converting_constructor (tree t)
+{
+ if (!CLASS_TYPE_P (t))
+ return false;
+
+ if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+ return false;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ {
+ tree fn = *iter;
+ tree parm = FUNCTION_FIRST_USER_PARMTYPE (fn);
+ if (parm == void_list_node
+ || !sufficient_parms_p (TREE_CHAIN (parm)))
+ /* Can't accept a single argument, so won't be considered for
+ conversion. */
+ continue;
+ if (TREE_CODE (fn) == TEMPLATE_DECL
+ || TREE_CHAIN (parm) != void_list_node)
+ /* Not a simple single parameter. */
+ return true;
+ if (TYPE_MAIN_VARIANT (non_reference (TREE_VALUE (parm)))
+ != DECL_CONTEXT (fn))
+ /* The single parameter has the wrong type. */
+ return true;
+ if (get_constraints (fn))
+ /* Constrained. */
+ return true;
+ }
+
+ return false;
+}
+
/* Returns true iff class T has a user-provided or explicit constructor. */
bool
return result;
}
-/* Return true if computing a conversion from FROM to TO might induce template
- instantiation. Conversely, if this predicate returns false then computing
- the conversion definitely won't induce template instantiation. */
+/* Return true if computing a conversion from FROM to TO might consider
+ user-defined conversions, which could lead to arbitrary template
+ instantiations (e.g. g++.dg/cpp2a/concepts-nondep1.C). If this predicate
+ returns false then computing the conversion definitely won't try UDCs.
+
+ Note that this restriction parallels LOOKUP_DEFAULTED for CWG1092, but in
+ this case we want the early filter to pass instead of fail. */
static bool
conversion_may_instantiate_p (tree to, tree from)
to = non_reference (to);
from = non_reference (from);
- bool ptr_conv_p = false;
- if (TYPE_PTR_P (to)
- && TYPE_PTR_P (from))
- {
- to = TREE_TYPE (to);
- from = TREE_TYPE (from);
- ptr_conv_p = true;
- }
-
- /* If one of the types is a not-yet-instantiated class template
- specialization, then computing the conversion might instantiate
- it in order to inspect bases, conversion functions and/or
- converting constructors. */
- if ((CLASS_TYPE_P (to)
- && !COMPLETE_TYPE_P (to)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (to))
- || (CLASS_TYPE_P (from)
- && !COMPLETE_TYPE_P (from)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (from)))
- return true;
-
- /* Converting from one pointer type to another, or between
- reference-related types, always yields a standard conversion. */
- if (ptr_conv_p || reference_related_p (to, from))
+ /* Converting between reference-related types is a standard conversion. */
+ if (reference_related_p (to, from))
return false;
/* Converting to a non-aggregate class type will consider its
user-declared constructors, which might induce instantiation. */
if (CLASS_TYPE_P (to)
- && CLASSTYPE_NON_AGGREGATE (to))
+ && type_has_converting_constructor (to))
return true;
/* Similarly, converting from a class type will consider its conversion
&& TYPE_HAS_CONVERSION (from))
return true;
- /* Otherwise, computing this conversion definitely won't induce
+ /* Otherwise, computing this conversion won't risk arbitrary
template instantiation. */
return false;
}
--- /dev/null
+// The from_range_t default ctor should not break the PR99599 workaround
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+struct S { T t; };
+
+template<typename T>
+concept C = sizeof(S<T>) > 0;
+
+struct I;
+
+struct from_range_t {
+ explicit from_range_t() = default;
+};
+inline constexpr from_range_t from_range;
+
+template<typename T>
+concept FromRange = __is_same_as (T, from_range_t);
+
+//#define WORKAROUND
+#ifdef WORKAROUND
+template<FromRange U, C T>
+void f(U, T*);
+#else
+template<C T>
+void f(from_range_t, T*);
+#endif
+
+void f(...);
+
+void g(I* p)
+{
+ ::f(0, p);
+}