| Submitter | Jason Merrill |
|---|---|
| Date | Sept. 5, 2011, 4:29 a.m. |
| Message ID | <4E64501D.5050806@redhat.com> |
| Download | mbox | patch |
| Permalink | /patch/113305/ |
| State | New |
| Headers | show |
Comments
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
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
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
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
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" }