[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