diff mbox series

[PR,c++/86246] ICE tsubst explicit operator call

Message ID ffc25cdd-2db2-ca0e-b168-a39dabdf95b9@acm.org
State New
Headers show
Series [PR,c++/86246] ICE tsubst explicit operator call | expand

Commit Message

Nathan Sidwell Nov. 15, 2018, 7:52 p.m. UTC
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
diff mbox series

Patch

2018-11-15  Nathan Sidwell  <nathan@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 ());
+}