mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-10 16:00:55 +08:00
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
This commit is contained in:
parent
3c5283a738
commit
6eb47b9829
@ -1,5 +1,22 @@
|
||||
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
|
||||
rather than DECL_TEMPLATE_INSTANTIATION.
|
||||
(cxx_eval_call_expression): Likewise.
|
||||
|
@ -4578,8 +4578,6 @@ 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.
|
||||
@ -4589,11 +4587,6 @@ finalize_literal_type_property (tree t)
|
||||
else if (CLASSTYPE_LITERAL_P (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
|
||||
&& !TYPE_HAS_CONSTEXPR_CTOR (t))
|
||||
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
|
||||
@ -5834,6 +5827,8 @@ finish_struct (tree t, tree attributes)
|
||||
else
|
||||
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 ())
|
||||
add_stmt (build_min (TAG_DEFN, t));
|
||||
|
||||
|
@ -5325,6 +5325,7 @@ extern void finish_handler_parms (tree, tree);
|
||||
extern void finish_handler (tree);
|
||||
extern void finish_cleanup (tree, tree);
|
||||
extern bool literal_type_p (tree);
|
||||
extern void check_deferred_constexpr_decls (void);
|
||||
extern tree validate_constexpr_fundecl (tree);
|
||||
extern tree register_constexpr_fundef (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,
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
if (!ensure_literal_type_for_constexpr_object (decl))
|
||||
DECL_DECLARED_CONSTEXPR_P (decl) = 0;
|
||||
|
||||
if (init && TREE_CODE (decl) == FUNCTION_DECL)
|
||||
@ -7206,7 +7200,10 @@ grokfndecl (tree ctype,
|
||||
if (inlinep)
|
||||
DECL_DECLARED_INLINE_P (decl) = 1;
|
||||
if (inlinep & 2)
|
||||
DECL_DECLARED_CONSTEXPR_P (decl) = true;
|
||||
{
|
||||
DECL_DECLARED_CONSTEXPR_P (decl) = true;
|
||||
validate_constexpr_fundecl (decl);
|
||||
}
|
||||
|
||||
DECL_EXTERNAL (decl) = 1;
|
||||
if (quals && TREE_CODE (type) == FUNCTION_TYPE)
|
||||
@ -12524,10 +12521,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
|
||||
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. */
|
||||
current_function_decl = decl1;
|
||||
|
||||
|
@ -8594,6 +8594,8 @@ instantiate_class_template_1 (tree type)
|
||||
pop_deferring_access_checks ();
|
||||
pop_tinst_level ();
|
||||
|
||||
check_deferred_constexpr_decls ();
|
||||
|
||||
/* The vtable for a template class can be emitted in any translation
|
||||
unit in which the class is instantiated. When there is no key
|
||||
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)
|
||||
if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
|
||||
&& !processing_template_decl)
|
||||
defaulted_late_check (r);
|
||||
validate_constexpr_fundecl (r);
|
||||
|
||||
apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
|
||||
args, complain, in_decl);
|
||||
|
@ -5336,7 +5336,11 @@ literal_type_p (tree t)
|
||||
|| TREE_CODE (t) == REFERENCE_TYPE)
|
||||
return true;
|
||||
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)
|
||||
return literal_type_p (strip_array_types (t));
|
||||
return false;
|
||||
@ -5350,13 +5354,17 @@ ensure_literal_type_for_constexpr_object (tree decl)
|
||||
{
|
||||
tree type = TREE_TYPE (decl);
|
||||
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
|
||||
&& !processing_template_decl
|
||||
/* The call to complete_type is just for initializer_list. */
|
||||
&& !literal_type_p (complete_type (type)))
|
||||
&& !processing_template_decl)
|
||||
{
|
||||
error ("the type %qT of constexpr variable %qD is not literal",
|
||||
type, decl);
|
||||
return NULL;
|
||||
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",
|
||||
type, decl);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
@ -5409,15 +5417,22 @@ retrieve_constexpr_fundef (tree fun)
|
||||
}
|
||||
|
||||
/* 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
|
||||
is_valid_constexpr_fn (tree fun, bool complain)
|
||||
static int
|
||||
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);
|
||||
bool ret = true;
|
||||
for (; parm != NULL; parm = TREE_CHAIN (parm))
|
||||
if (!literal_type_p (TREE_TYPE (parm)))
|
||||
IF_NON_LITERAL (TREE_TYPE (parm))
|
||||
{
|
||||
ret = false;
|
||||
if (complain)
|
||||
@ -5428,7 +5443,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
|
||||
if (!DECL_CONSTRUCTOR_P (fun))
|
||||
{
|
||||
tree rettype = TREE_TYPE (TREE_TYPE (fun));
|
||||
if (!literal_type_p (rettype))
|
||||
IF_NON_LITERAL (rettype)
|
||||
{
|
||||
ret = false;
|
||||
if (complain)
|
||||
@ -5436,18 +5451,51 @@ is_valid_constexpr_fn (tree fun, bool complain)
|
||||
rettype, fun);
|
||||
}
|
||||
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
|
||||
&& !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun))
|
||||
{
|
||||
ret = false;
|
||||
if (complain)
|
||||
error ("enclosing class of %q+#D is not a literal type", fun);
|
||||
IF_NON_LITERAL (DECL_CONTEXT (fun))
|
||||
{
|
||||
ret = false;
|
||||
if (complain)
|
||||
error ("enclosing class of %q+#D is not a literal type", fun);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
declaration. Otherwise return NULL. Issue appropriate diagnostics
|
||||
if necessary. Note that we only check the declaration, not the body
|
||||
@ -5456,13 +5504,22 @@ is_valid_constexpr_fn (tree fun, bool complain)
|
||||
tree
|
||||
validate_constexpr_fundecl (tree fun)
|
||||
{
|
||||
int valid;
|
||||
|
||||
if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
|
||||
return NULL;
|
||||
else if (DECL_CLONED_FUNCTION_P (fun))
|
||||
/* We already checked the original function. */
|
||||
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;
|
||||
return NULL;
|
||||
@ -6079,7 +6136,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
|
||||
if (DECL_TEMPLATE_INFO (fun)
|
||||
&& DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT
|
||||
(DECL_TI_TEMPLATE (fun))))
|
||||
is_valid_constexpr_fn (fun, true);
|
||||
is_valid_constexpr_fn (fun, true, /*defer_ok=*/false);
|
||||
}
|
||||
*non_constant_p = true;
|
||||
return t;
|
||||
|
@ -1,5 +1,8 @@
|
||||
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.
|
||||
|
||||
2011-05-11 Tobias Burnus <burnus@net-b.de>
|
||||
|
23
gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
Normal file
23
gcc/testsuite/g++.dg/cpp0x/constexpr-friend.C
Normal file
@ -0,0 +1,23 @@
|
||||
// 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" }
|
7
gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete1.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/constexpr-incomplete1.C
Normal file
@ -0,0 +1,7 @@
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
struct A
|
||||
{
|
||||
static constexpr A a = 1; // { dg-error "incomplete" }
|
||||
constexpr A(int i) { }
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user