Commit 6eb47b98 by Jason Merrill Committed by Jason Merrill

re PR c++/48948 ([C++0x] constexpr friend function cannot be defined in-class)

	PR c++/48948
	* semantics.c (validate_constexpr_fundecl): Defer checking if
	an argument type is being defined.
	(is_valid_constexpr_fn): Add defer_ok parm.
	(cxx_eval_call_expression): Adjust.
	(check_deferred_constexpr_decls): New.
	(literal_type_p): Make sure type isn't being defined.
	(ensure_literal_type_for_constexpr_object): Handle type being defined.
	* cp-tree.h: Declare check_deferred_constexpr_decls.
	* decl.c (grokfndecl): Call validate_constexpr_fundecl here.
	(start_preparsed_function, cp_finish_decl): Not here.
	* class.c (finalize_literal_type_property): Don't call
	validate_constexpr_fundecl.
	(finish_struct): Call check_deferred_constexpr_decls.
	* pt.c (tsubst_decl): Call validate_constexpr_fundecl.
	(instantiate_class_template): Call check_deferred_constexpr_decls.

From-SVN: r173683
parent 3c5283a7
2011-05-11 Jason Merrill <jason@redhat.com> 2011-05-11 Jason Merrill <jason@redhat.com>
PR c++/48948
* semantics.c (validate_constexpr_fundecl): Defer checking if
an argument type is being defined.
(is_valid_constexpr_fn): Add defer_ok parm.
(cxx_eval_call_expression): Adjust.
(check_deferred_constexpr_decls): New.
(literal_type_p): Make sure type isn't being defined.
(ensure_literal_type_for_constexpr_object): Handle type being defined.
* cp-tree.h: Declare check_deferred_constexpr_decls.
* decl.c (grokfndecl): Call validate_constexpr_fundecl here.
(start_preparsed_function, cp_finish_decl): Not here.
* class.c (finalize_literal_type_property): Don't call
validate_constexpr_fundecl.
(finish_struct): Call check_deferred_constexpr_decls.
* pt.c (tsubst_decl): Call validate_constexpr_fundecl.
(instantiate_class_template): Call check_deferred_constexpr_decls.
* semantics.c (validate_constexpr_fundecl): Check DECL_TEMPLATE_INFO * semantics.c (validate_constexpr_fundecl): Check DECL_TEMPLATE_INFO
rather than DECL_TEMPLATE_INSTANTIATION. rather than DECL_TEMPLATE_INSTANTIATION.
(cxx_eval_call_expression): Likewise. (cxx_eval_call_expression): Likewise.
......
...@@ -4578,8 +4578,6 @@ type_requires_array_cookie (tree type) ...@@ -4578,8 +4578,6 @@ type_requires_array_cookie (tree type)
static void static void
finalize_literal_type_property (tree t) finalize_literal_type_property (tree t)
{ {
tree fn;
if (cxx_dialect < cxx0x if (cxx_dialect < cxx0x
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
/* FIXME These constraints seem unnecessary; remove from standard. /* FIXME These constraints seem unnecessary; remove from standard.
...@@ -4589,11 +4587,6 @@ finalize_literal_type_property (tree t) ...@@ -4589,11 +4587,6 @@ finalize_literal_type_property (tree t)
else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t) else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
&& !TYPE_HAS_CONSTEXPR_CTOR (t)) && !TYPE_HAS_CONSTEXPR_CTOR (t))
CLASSTYPE_LITERAL_P (t) = false; CLASSTYPE_LITERAL_P (t) = 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 /* Check the validity of the bases and members declared in T. Add any
...@@ -5834,6 +5827,8 @@ finish_struct (tree t, tree attributes) ...@@ -5834,6 +5827,8 @@ finish_struct (tree t, tree attributes)
else else
error ("trying to finish struct, but kicked out due to previous parse errors"); error ("trying to finish struct, but kicked out due to previous parse errors");
check_deferred_constexpr_decls ();
if (processing_template_decl && at_function_scope_p ()) if (processing_template_decl && at_function_scope_p ())
add_stmt (build_min (TAG_DEFN, t)); add_stmt (build_min (TAG_DEFN, t));
......
...@@ -5325,6 +5325,7 @@ extern void finish_handler_parms (tree, tree); ...@@ -5325,6 +5325,7 @@ extern void finish_handler_parms (tree, tree);
extern void finish_handler (tree); extern void finish_handler (tree);
extern void finish_cleanup (tree, tree); extern void finish_cleanup (tree, tree);
extern bool literal_type_p (tree); extern bool literal_type_p (tree);
extern void check_deferred_constexpr_decls (void);
extern tree validate_constexpr_fundecl (tree); extern tree validate_constexpr_fundecl (tree);
extern tree register_constexpr_fundef (tree, tree); extern tree register_constexpr_fundef (tree, tree);
extern bool check_constexpr_ctor_body (tree, tree); extern bool check_constexpr_ctor_body (tree, tree);
......
...@@ -5911,13 +5911,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, ...@@ -5911,13 +5911,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
} }
} }
if (TREE_CODE (decl) == FUNCTION_DECL if (!ensure_literal_type_for_constexpr_object (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))
DECL_DECLARED_CONSTEXPR_P (decl) = 0; DECL_DECLARED_CONSTEXPR_P (decl) = 0;
if (init && TREE_CODE (decl) == FUNCTION_DECL) if (init && TREE_CODE (decl) == FUNCTION_DECL)
...@@ -7206,7 +7200,10 @@ grokfndecl (tree ctype, ...@@ -7206,7 +7200,10 @@ grokfndecl (tree ctype,
if (inlinep) if (inlinep)
DECL_DECLARED_INLINE_P (decl) = 1; DECL_DECLARED_INLINE_P (decl) = 1;
if (inlinep & 2) if (inlinep & 2)
{
DECL_DECLARED_CONSTEXPR_P (decl) = true; DECL_DECLARED_CONSTEXPR_P (decl) = true;
validate_constexpr_fundecl (decl);
}
DECL_EXTERNAL (decl) = 1; DECL_EXTERNAL (decl) = 1;
if (quals && TREE_CODE (type) == FUNCTION_TYPE) if (quals && TREE_CODE (type) == FUNCTION_TYPE)
...@@ -12524,10 +12521,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) ...@@ -12524,10 +12521,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
maybe_apply_pragma_weak (decl1); maybe_apply_pragma_weak (decl1);
} }
/* constexpr functions must have literal argument types and
literal return type. */
validate_constexpr_fundecl (decl1);
/* Reset this in case the call to pushdecl changed it. */ /* Reset this in case the call to pushdecl changed it. */
current_function_decl = decl1; current_function_decl = decl1;
......
...@@ -8594,6 +8594,8 @@ instantiate_class_template_1 (tree type) ...@@ -8594,6 +8594,8 @@ instantiate_class_template_1 (tree type)
pop_deferring_access_checks (); pop_deferring_access_checks ();
pop_tinst_level (); pop_tinst_level ();
check_deferred_constexpr_decls ();
/* The vtable for a template class can be emitted in any translation /* The vtable for a template class can be emitted in any translation
unit in which the class is instantiated. When there is no key unit in which the class is instantiated. When there is no key
method, however, finish_struct_1 will already have added TYPE to method, however, finish_struct_1 will already have added TYPE to
...@@ -9740,6 +9742,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -9740,6 +9742,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
&& !processing_template_decl) && !processing_template_decl)
defaulted_late_check (r); defaulted_late_check (r);
validate_constexpr_fundecl (r);
apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0, apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
args, complain, in_decl); args, complain, in_decl);
......
...@@ -5336,7 +5336,11 @@ literal_type_p (tree t) ...@@ -5336,7 +5336,11 @@ literal_type_p (tree t)
|| TREE_CODE (t) == REFERENCE_TYPE) || TREE_CODE (t) == REFERENCE_TYPE)
return true; return true;
if (CLASS_TYPE_P (t)) if (CLASS_TYPE_P (t))
return CLASSTYPE_LITERAL_P (t); {
/* We can't answer this question until the class is complete. */
gcc_assert (!TYPE_BEING_DEFINED (t) || errorcount);
return CLASSTYPE_LITERAL_P (complete_type (t));
}
if (TREE_CODE (t) == ARRAY_TYPE) if (TREE_CODE (t) == ARRAY_TYPE)
return literal_type_p (strip_array_types (t)); return literal_type_p (strip_array_types (t));
return false; return false;
...@@ -5350,14 +5354,18 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5350,14 +5354,18 @@ ensure_literal_type_for_constexpr_object (tree decl)
{ {
tree type = TREE_TYPE (decl); tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl) if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
&& !processing_template_decl && !processing_template_decl)
/* The call to complete_type is just for initializer_list. */ {
&& !literal_type_p (complete_type (type))) if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (type))
/* Don't complain here, we'll complain about incompleteness
when we try to initialize the variable. */;
else if (!literal_type_p (type))
{ {
error ("the type %qT of constexpr variable %qD is not literal", error ("the type %qT of constexpr variable %qD is not literal",
type, decl); type, decl);
return NULL; return NULL;
} }
}
return decl; return decl;
} }
...@@ -5409,15 +5417,22 @@ retrieve_constexpr_fundef (tree fun) ...@@ -5409,15 +5417,22 @@ retrieve_constexpr_fundef (tree fun)
} }
/* Check whether the parameter and return types of FUN are valid for a /* Check whether the parameter and return types of FUN are valid for a
constexpr function, and complain if COMPLAIN. */ constexpr function, and complain if COMPLAIN. If DEFER_OK is true,
return -1 if we can't tell yet because some of the types are still being
defined. */
static bool static int
is_valid_constexpr_fn (tree fun, bool complain) is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
{ {
#define IF_NON_LITERAL(TYPE) \
if (defer_ok && CLASS_TYPE_P (TYPE) && TYPE_BEING_DEFINED (TYPE)) \
return -1; \
else if (!literal_type_p (TYPE))
tree parm = FUNCTION_FIRST_USER_PARM (fun); tree parm = FUNCTION_FIRST_USER_PARM (fun);
bool ret = true; bool ret = true;
for (; parm != NULL; parm = TREE_CHAIN (parm)) for (; parm != NULL; parm = TREE_CHAIN (parm))
if (!literal_type_p (TREE_TYPE (parm))) IF_NON_LITERAL (TREE_TYPE (parm))
{ {
ret = false; ret = false;
if (complain) if (complain)
...@@ -5428,7 +5443,7 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5428,7 +5443,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
if (!DECL_CONSTRUCTOR_P (fun)) if (!DECL_CONSTRUCTOR_P (fun))
{ {
tree rettype = TREE_TYPE (TREE_TYPE (fun)); tree rettype = TREE_TYPE (TREE_TYPE (fun));
if (!literal_type_p (rettype)) IF_NON_LITERAL (rettype)
{ {
ret = false; ret = false;
if (complain) if (complain)
...@@ -5436,18 +5451,51 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5436,18 +5451,51 @@ is_valid_constexpr_fn (tree fun, bool complain)
rettype, fun); rettype, fun);
} }
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun))
&& !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) {
IF_NON_LITERAL (DECL_CONTEXT (fun))
{ {
ret = false; ret = false;
if (complain) 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);
} }
} }
}
return ret; return ret;
} }
/* We can't check the parameter and return types of a constexpr function
for literality until any open classes are complete, so we defer checking
of any constexpr functions declared in a class. */
static GTY(()) VEC(tree,gc) *deferred_constexpr_decls;
void
check_deferred_constexpr_decls (void)
{
unsigned i;
tree fn;
/* Some of the deferred decls might still need to be deferred,
so move the vector out of the way. */
VEC(tree,gc) *vec = deferred_constexpr_decls;
deferred_constexpr_decls = NULL;
FOR_EACH_VEC_ELT (tree, vec, i, fn)
validate_constexpr_fundecl (fn);
if (deferred_constexpr_decls == NULL)
{
/* If we didn't need to re-defer any, keep the same vector. */
VEC_truncate (tree, vec, 0);
deferred_constexpr_decls = vec;
}
else
/* Otherwise, discard the old vector. */
release_tree_vector (vec);
}
/* Return non-null if FUN certainly designates a valid constexpr function /* Return non-null if FUN certainly designates a valid constexpr function
declaration. Otherwise return NULL. Issue appropriate diagnostics declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body if necessary. Note that we only check the declaration, not the body
...@@ -5456,13 +5504,22 @@ is_valid_constexpr_fn (tree fun, bool complain) ...@@ -5456,13 +5504,22 @@ is_valid_constexpr_fn (tree fun, bool complain)
tree tree
validate_constexpr_fundecl (tree fun) validate_constexpr_fundecl (tree fun)
{ {
int valid;
if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun)) if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
return NULL; return NULL;
else if (DECL_CLONED_FUNCTION_P (fun)) else if (DECL_CLONED_FUNCTION_P (fun))
/* We already checked the original function. */ /* We already checked the original function. */
return fun; return fun;
if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun))) valid = is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun),
/*defer_ok=*/true);
if (valid < 0)
{
VEC_safe_push (tree, gc, deferred_constexpr_decls, fun);
return NULL;
}
else if (valid == 0)
{ {
DECL_DECLARED_CONSTEXPR_P (fun) = false; DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL; return NULL;
...@@ -6079,7 +6136,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6079,7 +6136,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (DECL_TEMPLATE_INFO (fun) if (DECL_TEMPLATE_INFO (fun)
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
(DECL_TI_TEMPLATE (fun)))) (DECL_TI_TEMPLATE (fun))))
is_valid_constexpr_fn (fun, true); is_valid_constexpr_fn (fun, true, /*defer_ok=*/false);
} }
*non_constant_p = true; *non_constant_p = true;
return t; return t;
......
2011-05-11 Jason Merrill <jason@redhat.com> 2011-05-11 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/constexpr-friend.C: New.
* g++.dg/cpp0x/constexpr-incomplete1.C: New.
* g++.dg/cpp0x/sfinae22.C: New. * g++.dg/cpp0x/sfinae22.C: New.
2011-05-11 Tobias Burnus <burnus@net-b.de> 2011-05-11 Tobias Burnus <burnus@net-b.de>
......
// PR c++/48948
// { dg-options -std=c++0x }
struct A { A(); };
struct B {
friend constexpr int f(B) { return 0; } // OK
friend constexpr int f(A) { return 0; } // { dg-error "constexpr" }
};
template <class T>
struct C
{
friend constexpr int f(C) { return 0; }
friend constexpr int g(C, A) { return 0; } // { dg-error "double" }
constexpr int m(C) { return 0; }
constexpr int m(A) { return 0; } // { dg-error "double" }
};
constexpr int i = f(C<int>());
constexpr int j = C<int>().m(C<int>());
constexpr int k = C<double>().m(A()); // { dg-error "not a constexpr function" }
constexpr int l = g(C<double>(),A()); // { dg-error "not a constexpr function" }
// { dg-options -std=c++0x }
struct A
{
static constexpr A a = 1; // { dg-error "incomplete" }
constexpr A(int i) { }
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment