We weren't noticing that 'expr.operator T()' is dependent if T is
dependent. Therefore we looked up 'operator T' at template definition
time and went down hill from there.
86246 and 87989 had different failure modes (one iced, one generated
wrong code), so adding both.
booted & tested on x86_64-linux, applying to trunk.
nathan
--
Nathan Sidwell
2018-11-15 Nathan Sidwell <nat...@acm.org>
PR c++/86246
PR c++/87989
* typeck.c (finish_class_member_access_expr): Conversion operator
to dependent type is dependent.
* g++.dg/template/pr86246.C: New.
* g++.dg/template/pr87989.C: New.
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 266191)
+++ cp/typeck.c (working copy)
@@ -2884,7 +2884,12 @@ finish_class_member_access_expr (cp_expr
expression is dependent. */
|| (TREE_CODE (name) == SCOPE_REF
&& TYPE_P (TREE_OPERAND (name, 0))
- && dependent_scope_p (TREE_OPERAND (name, 0))))
+ && dependent_scope_p (TREE_OPERAND (name, 0)))
+ /* If NAME is operator T where "T" is dependent, we can't
+ lookup until we instantiate the T. */
+ || (TREE_CODE (name) == IDENTIFIER_NODE
+ && IDENTIFIER_CONV_OP_P (name)
+ && dependent_type_p (TREE_TYPE (name))))
{
dependent:
return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
Index: testsuite/g++.dg/template/pr86246.C
===================================================================
--- testsuite/g++.dg/template/pr86246.C (revision 0)
+++ testsuite/g++.dg/template/pr86246.C (working copy)
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+// PR c++/86246 ICE in tsubst
+
+namespace std {
+ template<typename T> struct is_class {
+ static constexpr bool value = true;
+ };
+ template<> struct is_class<double> {
+ static constexpr bool value = false;
+ };
+}
+
+class MyClass {
+ public:
+ operator double() const {
+ return 1;
+ }
+ template<typename T>
+ operator T() const {
+ static_assert(std::is_class<T>::value, "problem");
+ return T();
+ }
+};
+
+template<typename T>
+void SetValue(const MyClass& obj, T* value) {
+ // erroneously dispatched to operator T when T is double
+ *value = obj.operator T();
+}
+
+int main() {
+ MyClass obj;
+ // works fine
+ obj.operator double ();
+ double x;
+ // error, when operator T is called in SetValue
+ SetValue(obj, &x);
+}
Index: testsuite/g++.dg/template/pr87989.C
===================================================================
--- testsuite/g++.dg/template/pr87989.C (revision 0)
+++ testsuite/g++.dg/template/pr87989.C (working copy)
@@ -0,0 +1,20 @@
+// PR c++/87989
+// { dg-do link }
+// Resolved to template instantiation rather than non-template fn.
+
+struct X {
+ template <class T> operator T() const; // no definition
+ operator float() const {return 0.f;}
+};
+
+template <class T>
+T f(const X &x) {
+ // Resoved in error to X::operator float<float>() const`
+ // instead of correct `X::operator float() const
+ return x.operator T();
+}
+
+int main ()
+{
+ return f<float>(X ());
+}