In 48296, the problem was that we were checking the parameter and return
types for literality too soon; we don't know whether the current class
is literal until we're done defining it. So let's be more patient about
checking.
The second patch changes the validation errors to point at the locus of
the function declaration in question, which improves their usefulness.
Tested x86_64-pc-linux-gnu, applying to trunk and 4.6.
commit ff8fcc903da4c162cdc99f5f967767148fe94d34
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Mar 29 00:45:42 2011 -0400
PR c++/48296
* decl.c (cp_finish_decl): Defer validation of constexpr member
functions.
* class.c (finalize_literal_type_property): Validate them here.
* semantics.c (is_valid_constexpr_fn): Don't check completeness.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index adae51f..24b8a31 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4549,6 +4549,8 @@ type_requires_array_cookie (tree type)
static void
finalize_literal_type_property (tree t)
{
+ tree fn;
+
if (cxx_dialect < cxx0x
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
/* FIXME These constraints seem unnecessary; remove from standard.
@@ -4559,18 +4561,10 @@ finalize_literal_type_property (tree t)
&& !TYPE_HAS_CONSTEXPR_CTOR (t))
CLASSTYPE_LITERAL_P (t) = false;
- if (!CLASSTYPE_LITERAL_P (t) && !CLASSTYPE_TEMPLATE_INSTANTIATION (t))
- {
- tree fn;
- for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
- if (DECL_DECLARED_CONSTEXPR_P (fn)
- && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
- && !DECL_CONSTRUCTOR_P (fn))
- {
- error ("enclosing class of %q+D is not a literal type", fn);
- DECL_DECLARED_CONSTEXPR_P (fn) = false;
- }
- }
+ for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+ if (DECL_DECLARED_CONSTEXPR_P (fn)
+ && TREE_CODE (fn) != TEMPLATE_DECL)
+ validate_constexpr_fundecl (fn);
}
/* Check the validity of the bases and members declared in T. Add any
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 895527c..16ccfaf 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5794,7 +5794,10 @@ cp_finish_decl (tree decl, tree init, bool
init_const_expr_p,
}
}
- if (TREE_CODE (decl) == FUNCTION_DECL)
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ /* For members, defer until finalize_literal_type_property. */
+ && (!DECL_CLASS_SCOPE_P (decl)
+ || !TYPE_BEING_DEFINED (DECL_CONTEXT (decl))))
validate_constexpr_fundecl (decl);
else if (!ensure_literal_type_for_constexpr_object (decl))
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index da8c016..f1c3d9a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5354,8 +5354,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
}
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
- && COMPLETE_TYPE_P (DECL_CONTEXT (fun))
- && !valid_type_in_constexpr_fundecl_p (DECL_CONTEXT (fun)))
+ && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
{
ret = false;
if (complain)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
new file mode 100644
index 0000000..4646f82
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-memfn1.C
@@ -0,0 +1,18 @@
+// PR c++/48296
+// { dg-options -std=c++0x }
+
+struct X
+{
+ constexpr X() { }
+ constexpr X f(X x) { return x; }
+ constexpr X g(X x);
+};
+
+constexpr X X::g(X x) { return x; }
+
+struct Y
+{
+ Y() { }
+ constexpr Y f(Y y); // { dg-error "constexpr" }
+ static constexpr Y g(Y y); // { dg-error "constexpr" }
+};
commit 055a6dbed418d3ab63420309433d8d7a9ddf172c
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Mar 28 19:49:41 2011 -0400
* semantics.c (is_valid_constexpr_fn): Specify input location.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6906c1b..da8c016 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5338,8 +5338,8 @@ is_valid_constexpr_fn (tree fun, bool complain)
{
ret = false;
if (complain)
- error ("invalid type for parameter %q#D of constexpr function",
- parm);
+ error ("invalid type for parameter %d of constexpr "
+ "function %q+#D", DECL_PARM_INDEX (parm), fun);
}
if (!DECL_CONSTRUCTOR_P (fun))
@@ -5349,7 +5349,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
{
ret = false;
if (complain)
- error ("invalid return type %qT of constexpr function %qD",
+ error ("invalid return type %qT of constexpr function %q+D",
rettype, fun);
}
@@ -5359,7 +5359,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
{
ret = false;
if (complain)
- error ("enclosing class of %q#D is not a literal type", fun);
+ error ("enclosing class of %q+#D is not a literal type", fun);
}
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
index a3706d6..183d3f7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag1.C
@@ -1,12 +1,11 @@
// Test that we explain why a template instantiation isn't constexpr
// { dg-options -std=c++0x }
-// { dg-prune-output "not a constexpr function" }
template <class T>
struct A
{
T t;
- constexpr int f() { return 42; }
+ constexpr int f() { return 42; } // { dg-error "enclosing class" }
};
struct B { B(); operator int(); };
@@ -14,8 +13,8 @@ struct B { B(); operator int(); };
constexpr A<int> ai = { 42 };
constexpr int i = ai.f();
-constexpr int b = A<B>().f(); // { dg-error "enclosing class" }
+constexpr int b = A<B>().f(); // { dg-error "not a constexpr function" }
template <class T>
-constexpr int f (T t) { return 42; }
-constexpr int x = f(B()); // { dg-error "parameter" }
+constexpr int f (T t) { return 42; } // { dg-error "parameter" }
+constexpr int x = f(B()); // { dg-error "constexpr function" }