For a normal function, we want a constexpr violation to be diagnosed
immediately so that the programmer can fix it. But for a template, we
don't want to complain about a particular instantiation if other
instantiations could be usable as constexpr functions. I've gone
through a couple of different checks to test this condition, but neither
was quite right, so now I've actually added the condition I want to
test: Is this function somehow generated by the compiler? In that case,
we let it pass and just complain if it gets used in a constant
expression; otherwise, we complain immediately.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 4c572dcb57f6e6073ebf8155f2a9ea254c90bf0f
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Sep 15 17:20:39 2011 -0400
* cp-tree.h (DECL_TEMPLOID_INSTANTIATION): New.
(DECL_GENERATED_P): New.
* class.c (finalize_literal_type_property): Use them.
* semantics.c (is_instantiation_of_constexpr): Likewise.
(register_constexpr_fundef): Likewise.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a4a7468..e398416 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4581,7 +4581,7 @@ finalize_literal_type_property (tree t)
&& !DECL_CONSTRUCTOR_P (fn))
{
DECL_DECLARED_CONSTEXPR_P (fn) = false;
- if (!DECL_TEMPLATE_INFO (fn))
+ if (!DECL_GENERATED_P (fn))
{
error ("enclosing class of constexpr non-static member "
"function %q+#D is not a literal type", fn);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8e52e28..bcfc3b3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3705,6 +3705,17 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION(DECL) \
(DECL_TEMPLATE_INFO (DECL) && !DECL_USE_TEMPLATE (DECL))
+/* Nonzero if DECL is a function generated from a function 'temploid',
+ i.e. template, member of class template, or dependent friend. */
+#define DECL_TEMPLOID_INSTANTIATION(DECL) \
+ (DECL_TEMPLATE_INSTANTIATION (DECL) \
+ || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (DECL))
+
+/* Nonzero if DECL is either defined implicitly by the compiler or
+ generated from a temploid. */
+#define DECL_GENERATED_P(DECL) \
+ (DECL_TEMPLOID_INSTANTIATION (DECL) || DECL_DEFAULTED_FN (DECL))
+
/* Nonzero iff we are currently processing a declaration for an
entity with its own template parameter list, and which is not a
full specialization. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f782df9..150805f 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3559,7 +3559,7 @@ emit_associated_thunks (tree fn)
static inline bool
is_instantiation_of_constexpr (tree fun)
{
- return (DECL_TEMPLATE_INFO (fun)
+ return (DECL_TEMPLOID_INSTANTIATION (fun)
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
(DECL_TI_TEMPLATE (fun))));
}
@@ -5820,7 +5820,7 @@ register_constexpr_fundef (tree fun, tree body)
constexpr_fundef entry;
constexpr_fundef **slot;
- if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
+ if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun)))
return NULL;
body = massage_constexpr_body (fun, body);
@@ -5833,13 +5833,13 @@ register_constexpr_fundef (tree fun, tree body)
if (!potential_rvalue_constant_expression (body))
{
- if (!DECL_TEMPLATE_INFO (fun))
+ if (!DECL_GENERATED_P (fun))
require_potential_rvalue_constant_expression (body);
return NULL;
}
if (DECL_CONSTRUCTOR_P (fun)
- && cx_check_missing_mem_inits (fun, body, !DECL_TEMPLATE_INFO (fun)))
+ && cx_check_missing_mem_inits (fun, body, !DECL_GENERATED_P (fun)))
return NULL;
/* Create the constexpr function table if necessary. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-generated1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-generated1.C
new file mode 100644
index 0000000..73ddc8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-generated1.C
@@ -0,0 +1,21 @@
+// { dg-options -std=c++0x }
+
+template <class T> struct A
+{
+ constexpr T f ();
+};
+
+int g();
+
+// We should complain about this.
+template<> constexpr int A<int>::f()
+{ return g(); } // { dg-error "non-constexpr" }
+
+// But not about this.
+struct B
+{
+ int i;
+ constexpr B(int i = g()):i(i) { }
+};
+struct C: B { };
+C c;