While thinking about this issue some more it occurred to me that this
deferral can be problematic for constructors, since we use whether or
not a constructor is really constexpr to decide whether or not a class
is literal. The rule that seems to me to make the most sense is to say
that if we don't know yet whether a constructor is really constexpr, it
doesn't satisfy the literal class requirement for a constexpr constructor.
Tested x86_64-pc-linux-gnu, applied to trunk.
commit 7919b46302ba6182d2dfa31d33eacbc2335de31e
Author: Jason Merrill <ja...@redhat.com>
Date: Thu May 12 12:33:08 2011 -0400
* cp-tree.h (DECL_DEFERRED_CONSTEXPR_CHECK): New.
* semantics.c (validate_constexpr_fundecl): Set it.
(check_deferred_constexpr_decls): Clear it.
(register_constexpr_fundef): Make sure it isn't set.
* decl.c (grok_special_member_properties): Check it.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ec59346..bcf78f8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -93,6 +93,7 @@ c-common.h, not after.
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR)
+ DECL_DEFERRED_CONSTEXPR_CHECK (in FUNCTION_DECL)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -2338,6 +2339,11 @@ struct GTY((variable_size)) lang_decl {
#define DECL_DECLARED_CONSTEXPR_P(DECL) \
DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
+/* True if we can't tell yet whether the argument/return types of DECL
+ are literal because one is still being defined. */
+#define DECL_DEFERRED_CONSTEXPR_CHECK(DECL) \
+ TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
+
/* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
template function. */
#define DECL_PRETTY_FUNCTION_P(NODE) \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 87be112..7939140 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10681,6 +10681,9 @@ grok_special_member_properties (tree decl)
TYPE_HAS_LIST_CTOR (class_type) = 1;
if (DECL_DECLARED_CONSTEXPR_P (decl)
+ /* It doesn't count if we can't tell yet whether or not
+ the constructor is actually constexpr. */
+ && !DECL_DEFERRED_CONSTEXPR_CHECK (decl)
&& !copy_fn_p (decl) && !move_fn_p (decl))
TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ffabad1..f1f3121 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5483,7 +5483,10 @@ check_deferred_constexpr_decls (void)
deferred_constexpr_decls = NULL;
FOR_EACH_VEC_ELT (tree, vec, i, fn)
- validate_constexpr_fundecl (fn);
+ {
+ DECL_DEFERRED_CONSTEXPR_CHECK (fn) = false;
+ validate_constexpr_fundecl (fn);
+ }
if (deferred_constexpr_decls == NULL)
{
@@ -5516,6 +5519,7 @@ validate_constexpr_fundecl (tree fun)
/*defer_ok=*/true);
if (valid < 0)
{
+ DECL_DEFERRED_CONSTEXPR_CHECK (fun) = true;
VEC_safe_push (tree, gc, deferred_constexpr_decls, fun);
return NULL;
}
@@ -5764,6 +5768,9 @@ register_constexpr_fundef (tree fun, tree body)
constexpr_fundef entry;
constexpr_fundef **slot;
+ gcc_assert (DECL_DECLARED_CONSTEXPR_P (fun)
+ && !DECL_DEFERRED_CONSTEXPR_CHECK (fun));
+
if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers
(DECL_CONTEXT (fun), body);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
new file mode 100644
index 0000000..7a9a24d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete2.C
@@ -0,0 +1,31 @@
+// A constructor that might or might not be constexpr doesn't make
+// its class literal.
+// { dg-options -std=c++0x }
+
+template <class T>
+struct B
+{
+ constexpr B(T) { }
+ constexpr B() {}
+};
+
+struct A
+{
+ B<A> b;
+};
+
+constexpr A a {};
+
+template <class T>
+struct C
+{
+ constexpr C(T) { }
+ C() {}
+};
+
+struct D
+{
+ C<D> c;
+};
+
+constexpr D d {}; // { dg-error "not literal" }