[PATCH] Fix PR c++/68948 (wrong code generation due to invalid constructor call)

Patrick Palka patrick@parcs.ath.cx
Fri Feb 5 04:21:00 GMT 2016


The compiler correctly detects and diagnoses invalid constructor calls
such as C::C () in a non-template context but it fails to do so while
processing a class template.  [ Section 3.4.3.1 of the standard is what
makes these forms of constructor calls illegal -- see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68948#c9  ]

In a non-template context this diagnosis would take place in
build_new_method_call, called from finish_call_expr, but while
processing a class template we may exit early out of finish_call_expr
and never call build_new_method_call.

Thus we never diagnose this invalid constructor call during template
processing.  So then during instantiation of the enclosing template we
call tsubst_baselink on this constructor call, during which the call to
lookup_fnfields returns NULL (because it finds the injected class type C
not the constructor C).  Because the lookup failed, tsubst_baselink
returns error_mark_node and this node persists all the way through to
gimplification where it silently gets discarded.

This patch fixes this problem by diagnosing these invalid constructor
calls in tsubst_baselink.  Alternatively, we can rewire finish_call_expr
avoid exiting early while processing a template if the call in question
is a constructor call.  I'm not sure which approach is better.  This
approach seems more conservative, since it's just attaching an error
message to an existing error path.

gcc/cp/ChangeLog:

	PR c++/68948
	* pt.c (tsubst_baselink): Diagnose an invalid constructor call
	if lookup_fnfields returns NULL_TREE and name we're looking up
	has the form A::A.

gcc/testsuite/ChangeLog:

	PR c++/68948
	* g++.dg/template/pr68948.C: New test.
---
 gcc/cp/pt.c                             | 10 +++++++-
 gcc/testsuite/g++.dg/template/pr68948.C | 41 +++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/pr68948.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4d405cf..91d0ef2 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13583,7 +13583,15 @@ tsubst_baselink (tree baselink, tree object_type,
       name = mangle_conv_op_name_for_type (optype);
     baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
     if (!baselink)
-      return error_mark_node;
+      {
+	if (constructor_name_p (name, qualifying_scope))
+	  {
+	    if (complain & tf_error)
+	      error ("cannot call constructor %<%T::%D%> directly",
+		     qualifying_scope, name);
+	  }
+	return error_mark_node;
+      }
 
     /* If lookup found a single function, mark it as used at this
        point.  (If it lookup found multiple functions the one selected
diff --git a/gcc/testsuite/g++.dg/template/pr68948.C b/gcc/testsuite/g++.dg/template/pr68948.C
new file mode 100644
index 0000000..ccbfb19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/pr68948.C
@@ -0,0 +1,41 @@
+// PR c++/68948
+
+struct B { B (); B (int); };
+
+struct Time : B { };
+
+/* Here, A and B are unrelated types.  */
+
+template <typename>
+struct A
+{
+  void TestBody ()
+  {
+    B::B (); // { dg-error "cannot call constructor" }
+    B::B::B (); // { dg-error "cannot call constructor" }
+    B::B (0); // { dg-error "cannot call constructor" }
+  }
+};
+
+/* Here, C is (indirectly) derived from B.  */
+
+template <typename g>
+struct C : Time
+{
+  void TestBody ()
+  {
+    B::B (); // { dg-error "cannot call constructor" }
+    B::B::B (); // { dg-error "cannot call constructor" }
+    B::B (0); // { dg-error "cannot call constructor" }
+    Time::B (0);
+  }
+};
+
+int
+main (void)
+{
+  A<int> a;
+  C<int> c;
+  a.TestBody ();
+  c.TestBody ();
+}
-- 
2.7.0.303.g36d4cae



More information about the Gcc-patches mailing list