Patchwork Fix PR c++/47172

login
register
mail settings
Submitter Dodji Seketeli
Date Feb. 9, 2011, 2:16 p.m.
Message ID <m339nxgunv.fsf@redhat.com>
Download mbox | patch
Permalink /patch/82469/
State New
Headers show

Comments

Dodji Seketeli - Feb. 9, 2011, 2:16 p.m.
Hello,

The code snippet below fails to compile in c++0x mode and compiles
fine in c++98.

    struct A
    {
	int f() const;
    };

    template <class T>
    struct B : A { };

    template <class T>
    struct C : B<T>
    {
	void g();
    };

    template <class T>
    void C<T>::g()
    {
	A::f(); //#0
    }

finish_expr_stmt fails on the call expression "A::f()" because it
doesn't notice that A::f() in #0 is type dependent [as its implicit
'this' is type dependent] and so it tries to fold it; and fails.

The patch below teaches type_dependent_expression_p to try harder to
look for type dependency in call expressions.

Tested on x86_64-unknown-linux-gnu against trunk.
Jason Merrill - Feb. 9, 2011, 6:23 p.m.
I think the right place to fix this is in finish_id_expression where we 
try to handle dependent calls differently, rather than 
type_dependent_expression_p; if we were to handle it in type_... we 
would need to make it fully recursive.

Jason

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d59f32a..5a70968 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18241,6 +18241,55 @@  type_dependent_expression_p (tree expression)
 	return dependent_type_p (type);
     }
 
+    if (TREE_CODE (expression) == CALL_EXPR)
+    {
+      int nargs, i;
+      tree fn;
+
+      if (dependent_type_p (TREE_TYPE (expression)))
+	return true;
+
+      fn = CALL_EXPR_FN (expression);
+
+      if (TREE_CODE (fn) == BASELINK)
+	{
+	  /* So this is a reference to a member function from a base.  */
+
+	  /* If the implicit "*this" is dependent then this reference
+	     to a member function is dependent.  */
+	  if (current_class_ref
+	      && dependent_type_p (TREE_TYPE (current_class_ref)))
+	    return true;
+
+	  /* If the qualifying scope is dependant then the expression
+	     is dependent.  */
+	  if (dependent_type_p (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn))))
+	    return true;
+	}
+      else if (TREE_CODE (fn) == COMPONENT_REF
+	       || TREE_CODE (fn) == OFFSET_REF)
+	{
+	  tree instance = TREE_OPERAND (fn, 0);
+	  tree method = TREE_OPERAND (fn, 1);
+
+	  if (type_dependent_expression_p (instance))
+	    return true;
+
+	  if (TREE_CODE (method) == IDENTIFIER_NODE)
+	    return false;
+
+	  if (type_dependent_expression_p (method))
+	    return true;
+	}
+
+      nargs = call_expr_nargs (expression);
+      for (i = 0; i < nargs; ++i)
+	if (type_dependent_expression_p (CALL_EXPR_ARG (expression, i)))
+	  return true;
+
+      expression = fn;
+    }
+
   if (TREE_CODE (expression) == SCOPE_REF)
     {
       tree scope = TREE_OPERAND (expression, 0);
diff --git a/gcc/testsuite/g++.dg/template/inherit6.C b/gcc/testsuite/g++.dg/template/inherit6.C
new file mode 100644
index 0000000..241a68e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/inherit6.C
@@ -0,0 +1,23 @@ 
+// Origin PR c++/47172
+// { dg-options "-std=c++0x" }
+// { dg-do compile }
+
+struct A
+{
+    int f() const;
+};
+
+template <class T>
+struct B : A { };
+
+template <class T>
+struct C : B<T>
+{
+    void g();
+};
+
+template <class T>
+void C<T>::g()
+{
+    A::f();
+}