Commit 0515f4d2 by Jason Merrill Committed by Jason Merrill

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

	PR c++/48948
	PR c++/49015
	* class.c (finalize_literal_type_property): Do check
	for constexpr member functions of non-literal class.
	(finish_struct): Don't call check_deferred_constexpr_decls.
	* cp-tree.h: Don't declare it.
	(DECL_DEFERRED_CONSTEXPR_CHECK): Remove.
	* decl.c (grok_special_member_properties): Don't check it
	(grokfnedcl): Don't call validate_constexpr_fundecl.
	(start_preparsed_function): Do call it.
	* pt.c (tsubst_decl): Don't call it.
	(instantiate_class_template_1): Don't call
	check_deferred_constexpr_decls.
	* semantics.c (literal_type_p): Check for any incompleteness.
	(ensure_literal_type_for_constexpr_object): Likewise.
	(is_valid_constexpr_fn): Revert deferral changes.
	(validate_constexpr_fundecl): Likewise.
	(register_constexpr_fundef): Likewise.
	(check_deferred_constexpr_decls): Remove.

From-SVN: r173869
parent 41d471d6
2011-05-18 Jason Merrill <jason@redhat.com>
PR c++/48948
PR c++/49015
* class.c (finalize_literal_type_property): Do check
for constexpr member functions of non-literal class.
(finish_struct): Don't call check_deferred_constexpr_decls.
* cp-tree.h: Don't declare it.
(DECL_DEFERRED_CONSTEXPR_CHECK): Remove.
* decl.c (grok_special_member_properties): Don't check it
(grokfnedcl): Don't call validate_constexpr_fundecl.
(start_preparsed_function): Do call it.
* pt.c (tsubst_decl): Don't call it.
(instantiate_class_template_1): Don't call
check_deferred_constexpr_decls.
* semantics.c (literal_type_p): Check for any incompleteness.
(ensure_literal_type_for_constexpr_object): Likewise.
(is_valid_constexpr_fn): Revert deferral changes.
(validate_constexpr_fundecl): Likewise.
(register_constexpr_fundef): Likewise.
(check_deferred_constexpr_decls): Remove.
2011-05-16 Jason Merrill <jason@redhat.com> 2011-05-16 Jason Merrill <jason@redhat.com>
PR c++/48969 PR c++/48969
......
...@@ -4582,6 +4582,8 @@ type_requires_array_cookie (tree type) ...@@ -4582,6 +4582,8 @@ 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.
...@@ -4591,6 +4593,18 @@ finalize_literal_type_property (tree t) ...@@ -4591,6 +4593,18 @@ 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;
if (!CLASSTYPE_LITERAL_P (t))
for (fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
if (DECL_DECLARED_CONSTEXPR_P (fn)
&& TREE_CODE (fn) != TEMPLATE_DECL
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
&& !DECL_CONSTRUCTOR_P (fn))
{
DECL_DECLARED_CONSTEXPR_P (fn) = false;
if (!DECL_TEMPLATE_INFO (fn))
error ("enclosing class of %q+#D is not a literal type", 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
...@@ -5831,8 +5845,6 @@ finish_struct (tree t, tree attributes) ...@@ -5831,8 +5845,6 @@ 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));
......
...@@ -93,7 +93,6 @@ c-common.h, not after. ...@@ -93,7 +93,6 @@ c-common.h, not after.
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR) LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR)
TARGET_EXPR_DIRECT_INIT_P (in TARGET_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). 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV) ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK) FN_TRY_BLOCK_P (in TRY_BLOCK)
...@@ -2345,11 +2344,6 @@ struct GTY((variable_size)) lang_decl { ...@@ -2345,11 +2344,6 @@ struct GTY((variable_size)) lang_decl {
#define DECL_DECLARED_CONSTEXPR_P(DECL) \ #define DECL_DECLARED_CONSTEXPR_P(DECL) \
DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (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 /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
template function. */ template function. */
#define DECL_PRETTY_FUNCTION_P(NODE) \ #define DECL_PRETTY_FUNCTION_P(NODE) \
...@@ -5337,7 +5331,6 @@ extern void finish_handler_parms (tree, tree); ...@@ -5337,7 +5331,6 @@ 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);
......
...@@ -7200,10 +7200,7 @@ grokfndecl (tree ctype, ...@@ -7200,10 +7200,7 @@ 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)
...@@ -10681,9 +10678,6 @@ grok_special_member_properties (tree decl) ...@@ -10681,9 +10678,6 @@ grok_special_member_properties (tree decl)
TYPE_HAS_LIST_CTOR (class_type) = 1; TYPE_HAS_LIST_CTOR (class_type) = 1;
if (DECL_DECLARED_CONSTEXPR_P (decl) 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)) && !copy_fn_p (decl) && !move_fn_p (decl))
TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1; TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
} }
...@@ -12524,6 +12518,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags) ...@@ -12524,6 +12518,10 @@ 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;
......
...@@ -8595,8 +8595,6 @@ instantiate_class_template_1 (tree type) ...@@ -8595,8 +8595,6 @@ 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
...@@ -9743,7 +9741,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) ...@@ -9743,7 +9741,6 @@ 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);
......
...@@ -5337,9 +5337,9 @@ literal_type_p (tree t) ...@@ -5337,9 +5337,9 @@ literal_type_p (tree t)
return true; return true;
if (CLASS_TYPE_P (t)) if (CLASS_TYPE_P (t))
{ {
/* We can't answer this question until the class is complete. */ t = complete_type (t);
gcc_assert (!TYPE_BEING_DEFINED (t) || errorcount); gcc_assert (COMPLETE_TYPE_P (t) || errorcount);
return CLASSTYPE_LITERAL_P (complete_type (t)); return CLASSTYPE_LITERAL_P (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));
...@@ -5356,7 +5356,7 @@ ensure_literal_type_for_constexpr_object (tree decl) ...@@ -5356,7 +5356,7 @@ ensure_literal_type_for_constexpr_object (tree 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)
{ {
if (CLASS_TYPE_P (type) && TYPE_BEING_DEFINED (type)) if (CLASS_TYPE_P (type) && !COMPLETE_TYPE_P (complete_type (type)))
/* Don't complain here, we'll complain about incompleteness /* Don't complain here, we'll complain about incompleteness
when we try to initialize the variable. */; when we try to initialize the variable. */;
else if (!literal_type_p (type)) else if (!literal_type_p (type))
...@@ -5417,22 +5417,15 @@ retrieve_constexpr_fundef (tree fun) ...@@ -5417,22 +5417,15 @@ 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. If DEFER_OK is true, constexpr function, and complain if COMPLAIN. */
return -1 if we can't tell yet because some of the types are still being
defined. */
static int static bool
is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) is_valid_constexpr_fn (tree fun, bool complain)
{ {
#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_NON_LITERAL (TREE_TYPE (parm)) if (!literal_type_p (TREE_TYPE (parm)))
{ {
ret = false; ret = false;
if (complain) if (complain)
...@@ -5443,7 +5436,7 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) ...@@ -5443,7 +5436,7 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
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_NON_LITERAL (rettype) if (!literal_type_p (rettype))
{ {
ret = false; ret = false;
if (complain) if (complain)
...@@ -5451,54 +5444,19 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok) ...@@ -5451,54 +5444,19 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
rettype, fun); rettype, fun);
} }
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) /* Check this again here for cxx_eval_call_expression. */
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
&& !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
{ {
IF_NON_LITERAL (DECL_CONTEXT (fun)) ret = false;
{ if (complain)
ret = false; error ("enclosing class of %q+#D is not a literal type", fun);
if (complain)
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)
{
DECL_DEFERRED_CONSTEXPR_CHECK (fn) = false;
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
...@@ -5507,23 +5465,13 @@ check_deferred_constexpr_decls (void) ...@@ -5507,23 +5465,13 @@ check_deferred_constexpr_decls (void)
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;
valid = is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun), if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
/*defer_ok=*/true);
if (valid < 0)
{
DECL_DEFERRED_CONSTEXPR_CHECK (fun) = true;
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;
...@@ -5768,9 +5716,6 @@ register_constexpr_fundef (tree fun, tree body) ...@@ -5768,9 +5716,6 @@ register_constexpr_fundef (tree fun, tree body)
constexpr_fundef entry; constexpr_fundef entry;
constexpr_fundef **slot; constexpr_fundef **slot;
gcc_assert (DECL_DECLARED_CONSTEXPR_P (fun)
&& !DECL_DEFERRED_CONSTEXPR_CHECK (fun));
if (DECL_CONSTRUCTOR_P (fun)) if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers body = build_constexpr_constructor_member_initializers
(DECL_CONTEXT (fun), body); (DECL_CONTEXT (fun), body);
...@@ -6143,7 +6088,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6143,7 +6088,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, /*defer_ok=*/false); is_valid_constexpr_fn (fun, true);
} }
*non_constant_p = true; *non_constant_p = true;
return t; return t;
......
2011-05-18 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/constexpr-incomplete3.C: New.
* g++.dg/cpp0x/constexpr-incomplete2.C: Adjust.
* g++.dg/cpp0x/constexpr-memfn1.C: Adjust.
2011-05-18 Stuart Henderson <shenders@gcc.gnu.org> 2011-05-18 Stuart Henderson <shenders@gcc.gnu.org>
* gcc.target/bfin/mcpu-bf592.c: New test. * gcc.target/bfin/mcpu-bf592.c: New test.
......
// A constructor that might or might not be constexpr doesn't make // A constructor that might or might not be constexpr still makes
// its class literal. // its class literal.
// { dg-options -std=c++0x } // { dg-options -std=c++0x }
...@@ -28,4 +28,4 @@ struct D ...@@ -28,4 +28,4 @@ struct D
C<D> c; C<D> c;
}; };
constexpr D d {}; // { dg-error "not literal" } constexpr D d {}; // { dg-error "not a constexpr function" }
// PR c++/49015
// { dg-options -std=c++0x }
class A;
class B {
friend constexpr B f(A); // Line 5
};
class A {};
constexpr B f(A) { return B(); } // Line 10
...@@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; } ...@@ -13,6 +13,6 @@ constexpr X X::g(X x) { return x; }
struct Y struct Y
{ {
Y() { } Y() { }
constexpr Y f(Y y); // { dg-error "constexpr" } constexpr Y f(Y y); // { dg-error "not a literal type" }
static constexpr Y g(Y y); // { dg-error "constexpr" } static constexpr Y g(Y y) {} // { dg-error "constexpr" }
}; };
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