diff mbox

C++ PATCHes for core 1358, 1360, c++/50248 (constexpr, templates, default constructor)

Message ID 4E64501D.5050806@redhat.com
State New
Headers show

Commit Message

Jason Merrill Sept. 5, 2011, 4:29 a.m. UTC
At the Bloomington C++ meeting we discussed some issues with the 
constexpr specification that the clang team encountered while trying to 
implement it.  Among the issues was a problem that also came up recently 
for us as BZ 50248: if the constexpr-ness of a template instantiation 
depends on its body, we need to instantiate it in order to decide 
whether or not an implicitly-declared function that uses it is 
constexpr.  The resolution of DR 1358 is that an instantiation of a 
constexpr template is constexpr even if it can never produce a constant 
expression.

The second patch is related to DR 1360, where the clang team was 
complaining that deciding whether or not a class is literal requires the 
implicit declaration of the default constructor, which they would like 
to do lazily.  We seem to have agreed that it can be avoided in the 
cases where doing such is useful, but while looking at this I noticed a 
bug in our handling of this stuff: the function 
synthesized_default_constructor_is_constexpr was only right for trivial 
constructors.  So now I've renamed it accordingly, and force the 
implicit declaration for the non-trivial case.

Tested x86_64-pc-linux-gnu, applying to trunk.

Comments

Gabriel Dos Reis Sept. 5, 2011, 5:04 a.m. UTC | #1
On Sun, Sep 4, 2011 at 11:29 PM, Jason Merrill <jason@redhat.com> wrote:
> At the Bloomington C++ meeting we discussed some issues with the constexpr
> specification that the clang team encountered while trying to implement it.
>  Among the issues was a problem that also came up recently for us as BZ
> 50248: if the constexpr-ness of a template instantiation depends on its
> body, we need to instantiate it in order to decide whether or not an
> implicitly-declared function that uses it is constexpr.  The resolution of
> DR 1358 is that an instantiation of a constexpr template is constexpr even
> if it can never produce a constant expression.

I am lost: so no diagnostic is issued but the function is deemed constexpr?

-- Gaby
Jason Merrill Sept. 5, 2011, 6:17 a.m. UTC | #2
On 09/05/2011 01:04 AM, Gabriel Dos Reis wrote:
> On Sun, Sep 4, 2011 at 11:29 PM, Jason Merrill<jason@redhat.com>  wrote:
>> At the Bloomington C++ meeting we discussed some issues with the constexpr
>> specification that the clang team encountered while trying to implement it.
>>   Among the issues was a problem that also came up recently for us as BZ
>> 50248: if the constexpr-ness of a template instantiation depends on its
>> body, we need to instantiate it in order to decide whether or not an
>> implicitly-declared function that uses it is constexpr.  The resolution of
>> DR 1358 is that an instantiation of a constexpr template is constexpr even
>> if it can never produce a constant expression.
>
> I am lost: so no diagnostic is issued but the function is deemed constexpr?

For a template instantiation, correct.  If the function doesn't satisfy 
the constexpr requirements, we don't store it in the hash table and we 
complain about it if it's used in a constant expression.  We don't want 
a function to change constexpr status depending on whether it has been 
instantiated or not, so they should just stay constexpr.

Jason
H.J. Lu Sept. 5, 2011, 7:07 p.m. UTC | #3
On Sun, Sep 4, 2011 at 9:29 PM, Jason Merrill <jason@redhat.com> wrote:
> At the Bloomington C++ meeting we discussed some issues with the constexpr
> specification that the clang team encountered while trying to implement it.
>  Among the issues was a problem that also came up recently for us as BZ
> 50248: if the constexpr-ness of a template instantiation depends on its
> body, we need to instantiate it in order to decide whether or not an
> implicitly-declared function that uses it is constexpr.  The resolution of
> DR 1358 is that an instantiation of a constexpr template is constexpr even
> if it can never produce a constant expression.
>
> The second patch is related to DR 1360, where the clang team was complaining
> that deciding whether or not a class is literal requires the implicit
> declaration of the default constructor, which they would like to do lazily.
>  We seem to have agreed that it can be avoided in the cases where doing such
> is useful, but while looking at this I noticed a bug in our handling of this
> stuff: the function synthesized_default_constructor_is_constexpr was only
> right for trivial constructors.  So now I've renamed it accordingly, and
> force the implicit declaration for the non-trivial case.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50296
H.J. Lu June 15, 2012, 3:06 a.m. UTC | #4
On Mon, Sep 5, 2011 at 12:07 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Sun, Sep 4, 2011 at 9:29 PM, Jason Merrill <jason@redhat.com> wrote:
>> At the Bloomington C++ meeting we discussed some issues with the constexpr
>> specification that the clang team encountered while trying to implement it.
>>  Among the issues was a problem that also came up recently for us as BZ
>> 50248: if the constexpr-ness of a template instantiation depends on its
>> body, we need to instantiate it in order to decide whether or not an
>> implicitly-declared function that uses it is constexpr.  The resolution of
>> DR 1358 is that an instantiation of a constexpr template is constexpr even
>> if it can never produce a constant expression.
>>
>> The second patch is related to DR 1360, where the clang team was complaining
>> that deciding whether or not a class is literal requires the implicit
>> declaration of the default constructor, which they would like to do lazily.
>>  We seem to have agreed that it can be avoided in the cases where doing such
>> is useful, but while looking at this I noticed a bug in our handling of this
>> stuff: the function synthesized_default_constructor_is_constexpr was only
>> right for trivial constructors.  So now I've renamed it accordingly, and
>> force the implicit declaration for the non-trivial case.
>>
>> Tested x86_64-pc-linux-gnu, applying to trunk.
>>
>
> This caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50296
>

This also caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53202
diff mbox

Patch

commit 2f4a14c2ce37bbba87e45977c1314ab7984baf72
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Aug 19 09:21:45 2011 -0400

    	* class.c (trivial_default_constructor_is_constexpr): Rename from
    	synthesized_default_constructor_is_constexpr.
    	(type_has_constexpr_default_constructor): Adjust.
    	(add_implicitly_declared_members): Call it instead.
    	(explain_non_literal_class): Explain about non-constexpr default ctor.
    	* cp-tree.h: Adjust.
    	* method.c (synthesized_method_walk): Adjust.
    	* semantics.c (explain_invalid_constexpr_fn): Handle defaulted
    	functions, too.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 2a4bc77..a4a7468 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2726,7 +2726,8 @@  add_implicitly_declared_members (tree t,
       CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1;
       if (cxx_dialect >= cxx0x)
 	TYPE_HAS_CONSTEXPR_CTOR (t)
-	  = synthesized_default_constructor_is_constexpr (t);
+	  /* This might force the declaration.  */
+	  = type_has_constexpr_default_constructor (t);
     }
 
   /* [class.ctor]
@@ -4355,15 +4356,15 @@  type_has_user_provided_default_constructor (tree t)
   return false;
 }
 
-/* Returns true iff for class T, a synthesized default constructor
+/* Returns true iff for class T, a trivial synthesized default constructor
    would be constexpr.  */
 
 bool
-synthesized_default_constructor_is_constexpr (tree t)
+trivial_default_constructor_is_constexpr (tree t)
 {
-  /* A defaulted default constructor is constexpr
+  /* A defaulted trivial default constructor is constexpr
      if there is nothing to initialize.  */
-  /* FIXME adjust for non-static data member initializers.  */
+  gcc_assert (!TYPE_HAS_COMPLEX_DFLT (t));
   return is_really_empty_class (t);
 }
 
@@ -4381,7 +4382,12 @@  type_has_constexpr_default_constructor (tree t)
       return false;
     }
   if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
-    return synthesized_default_constructor_is_constexpr (t);
+    {
+      if (!TYPE_HAS_COMPLEX_DFLT (t))
+	return trivial_default_constructor_is_constexpr (t);
+      /* Non-trivial, we need to check subobject constructors.  */
+      lazily_declare_fn (sfk_constructor, t);
+    }
   fns = locate_ctor (t);
   return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
 }
@@ -4608,9 +4614,14 @@  explain_non_literal_class (tree t)
   else if (CLASSTYPE_NON_AGGREGATE (t)
 	   && !TYPE_HAS_TRIVIAL_DFLT (t)
 	   && !TYPE_HAS_CONSTEXPR_CTOR (t))
-    inform (0, "  %q+T is not an aggregate, does not have a trivial "
-	    "default constructor, and has no constexpr constructor that "
-	    "is not a copy or move constructor", t);
+    {
+      inform (0, "  %q+T is not an aggregate, does not have a trivial "
+	      "default constructor, and has no constexpr constructor that "
+	      "is not a copy or move constructor", t);
+      if (TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
+	  && !type_has_user_provided_default_constructor (t))
+	explain_invalid_constexpr_fn (locate_ctor (t));
+    }
   else
     {
       tree binfo, base_binfo, field; int i;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d18599b..cf6c056 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4823,7 +4823,7 @@  extern tree in_class_defaulted_default_constructor (tree);
 extern bool user_provided_p			(tree);
 extern bool type_has_user_provided_constructor  (tree);
 extern bool type_has_user_provided_default_constructor (tree);
-extern bool synthesized_default_constructor_is_constexpr (tree);
+extern bool trivial_default_constructor_is_constexpr (tree);
 extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor		(tree);
 extern bool type_has_move_constructor		(tree);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 74a3bdb..5b24f8f 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1187,7 +1187,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       && (!copy_arg_p || cxx_dialect < cxx0x))
     {
       if (constexpr_p && sfk == sfk_constructor)
-	*constexpr_p = synthesized_default_constructor_is_constexpr (ctype);
+	*constexpr_p = trivial_default_constructor_is_constexpr (ctype);
       return;
     }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fd96d70..bdc4cf2 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5881,8 +5881,9 @@  explain_invalid_constexpr_fn (tree fun)
   static struct pointer_set_t *diagnosed;
   tree body;
   location_t save_loc;
-  /* Only diagnose instantiations of constexpr templates.  */
-  if (!is_instantiation_of_constexpr (fun))
+  /* Only diagnose defaulted functions or instantiations.  */
+  if (!DECL_DEFAULTED_FN (fun)
+      && !is_instantiation_of_constexpr (fun))
     return;
   if (diagnosed == NULL)
     diagnosed = pointer_set_create ();
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-default-ctor.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-default-ctor.C
new file mode 100644
index 0000000..d3868b5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-default-ctor.C
@@ -0,0 +1,12 @@ 
+// { dg-options -std=c++0x }
+
+struct A {
+  int i;
+  constexpr A():i(42) { };
+};
+struct B: A { };
+constexpr int f(B b) { return b.i; }
+
+struct C { C(); };	       // { dg-message "calls non-constexpr" }
+struct D: C { };	       // { dg-message "no constexpr constructor" }
+constexpr int g(D d) { return 42; } // { dg-error "invalid type" }