diff mbox

[C++,Patch/RFC] PR 60389

Message ID 53160037.502@oracle.com
State New
Headers show

Commit Message

Paolo Carlini March 4, 2014, 4:32 p.m. UTC
Hi,

this regression is just an ICE on invalid, but I'm finding it somewhat 
tricky. Let's see if I can explain clearly enough what I figured out so far.

The problem manifests itself when is_valid_constexpr_fn is called by 
explain_invalid_constexpr_fn with a TEMPLATE_DECL (the inherited 
template constructor) as the fun argument and FUNCTION_FIRST_USER_PARM 
cannot be used on it. This happens because explain_invalid_constexpr_fn 
(called from the second half of explain_non_literal_class) doesn't early 
return via:

/* Only diagnose defaulted functions or instantiations. */
if (!DECL_DEFAULTED_FN (fun)
&& !is_instantiation_of_constexpr (fun))
return;

because we internally represent inherited *template* constructors too as 
defaulted. Thus, the idea of handling those specially per the first 
draft I'm attaching. In fact, note that if we try to fix up 
is_valid_constexpr_fn (like in the second draft I'm attaching below), we 
get a final error message of the form

60389.C:13:12: note: ‘template<class ... T> B::B(T ...)’ is not usable 
as a constexpr function because:
using A::A;
^
60389.C:13:12: error: invalid type for parameter 1 of constexpr function 
‘template<class ... T> B::B(T ...)’

which I find quite confusing, because that parameter is a 
TYPE_PACK_EXPANSION (for which the literal_type_p check in 
is_valid_constexpr_fn returns false) but in fact a B::B() is needed... 
Note, moreover, that if the user tries to "force" the compilation by 
simply declaring the A::A(T...) constructor explicitly constexpr, the 
compilation in fact succeeds (at least, with GCC ;) and that doesn't 
appear to make much sense vs the latter error message. So, what shall we 
do? Just patch 1 (with a comment explaining the early return)? Or Patch 
2 and reconsider these issues later? Or something else?

Thanks!
Paolo.

/////////////////////////

Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 208317)
+++ cp/semantics.c	(working copy)
@@ -7430,7 +7430,7 @@ retrieve_constexpr_fundef (tree fun)
 static bool
 is_valid_constexpr_fn (tree fun, bool complain)
 {
-  tree parm = FUNCTION_FIRST_USER_PARM (fun);
+  tree parm = FUNCTION_FIRST_USER_PARM (STRIP_TEMPLATE (fun));
   bool ret = true;
   for (; parm != NULL; parm = TREE_CHAIN (parm))
     if (!literal_type_p (TREE_TYPE (parm)))
Index: testsuite/g++.dg/cpp0x/inh-ctor19.C
===================================================================
--- testsuite/g++.dg/cpp0x/inh-ctor19.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/inh-ctor19.C	(working copy)
@@ -0,0 +1,14 @@
+// PR c++/60389
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  template<typename...T> A(T...) {}
+};
+
+struct B : A
+{
+  using A::A;   // { dg-error "invalid type" }
+};
+
+constexpr B b;  // { dg-error "literal" }

Comments

Jason Merrill March 7, 2014, 5:36 p.m. UTC | #1
Inherited constructors inherit 'constexpr' from the designated base; 
B::B isn't constexpr because A::A isn't, and we should say that at the 
beginning of is_valid_constexpr_fn.

Jason
diff mbox

Patch

Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 208317)
+++ cp/semantics.c	(working copy)
@@ -8002,7 +8002,9 @@  explain_invalid_constexpr_fn (tree fun)
   tree body;
   location_t save_loc;
   /* Only diagnose defaulted functions or instantiations.  */
-  if (!DECL_DEFAULTED_FN (fun)
+  if ((!DECL_DEFAULTED_FN (fun)
+       || (DECL_INHERITED_CTOR_BASE (fun)
+	   && TREE_CODE (fun) == TEMPLATE_DECL))
       && !is_instantiation_of_constexpr (fun))
     return;
   if (diagnosed == NULL)
Index: testsuite/g++.dg/cpp0x/inh-ctor19.C
===================================================================
--- testsuite/g++.dg/cpp0x/inh-ctor19.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/inh-ctor19.C	(working copy)
@@ -0,0 +1,14 @@ 
+// PR c++/60389
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  template<typename...T> A(T...) {}
+};
+
+struct B : A
+{
+  using A::A;
+};
+
+constexpr B b;  // { dg-error "literal" }