commit f2a2c7b6af06123b5f81bd474b60bddfe9b58550
Author: Jason Merrill <jason@redhat.com>
Date: Mon May 16 17:21:17 2011 -0400
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.
@@ -4582,6 +4582,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.
@@ -4591,6 +4593,18 @@ 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;
+
+ 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
@@ -5831,8 +5845,6 @@ 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));
@@ -93,7 +93,6 @@ c-common.h, not after.
TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE)
LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_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).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -2345,11 +2344,6 @@ struct GTY((variable_size)) lang_decl {
#define DECL_DECLARED_CONSTEXPR_P(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
template function. */
#define DECL_PRETTY_FUNCTION_P(NODE) \
@@ -5337,7 +5331,6 @@ 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);
@@ -7200,10 +7200,7 @@ grokfndecl (tree ctype,
if (inlinep)
DECL_DECLARED_INLINE_P (decl) = 1;
if (inlinep & 2)
- {
- DECL_DECLARED_CONSTEXPR_P (decl) = true;
- validate_constexpr_fundecl (decl);
- }
+ DECL_DECLARED_CONSTEXPR_P (decl) = true;
DECL_EXTERNAL (decl) = 1;
if (quals && TREE_CODE (type) == FUNCTION_TYPE)
@@ -10681,9 +10678,6 @@ grok_special_member_properties (tree decl)
TYPE_HAS_LIST_CTOR (class_type) = 1;
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))
TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
}
@@ -12524,6 +12518,10 @@ 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;
@@ -8595,8 +8595,6 @@ 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
@@ -9743,7 +9741,6 @@ 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);
@@ -5337,9 +5337,9 @@ literal_type_p (tree t)
return true;
if (CLASS_TYPE_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));
+ t = complete_type (t);
+ gcc_assert (COMPLETE_TYPE_P (t) || errorcount);
+ return CLASSTYPE_LITERAL_P (t);
}
if (TREE_CODE (t) == ARRAY_TYPE)
return literal_type_p (strip_array_types (t));
@@ -5356,7 +5356,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (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
when we try to initialize the variable. */;
else if (!literal_type_p (type))
@@ -5417,22 +5417,15 @@ retrieve_constexpr_fundef (tree fun)
}
/* Check whether the parameter and return types of FUN are valid for a
- 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. */
+ constexpr function, and complain if COMPLAIN. */
-static int
-is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
+static bool
+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);
bool ret = true;
for (; parm != NULL; parm = TREE_CHAIN (parm))
- IF_NON_LITERAL (TREE_TYPE (parm))
+ if (!literal_type_p (TREE_TYPE (parm)))
{
ret = false;
if (complain)
@@ -5443,7 +5436,7 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
if (!DECL_CONSTRUCTOR_P (fun))
{
tree rettype = TREE_TYPE (TREE_TYPE (fun));
- IF_NON_LITERAL (rettype)
+ if (!literal_type_p (rettype))
{
ret = false;
if (complain)
@@ -5451,54 +5444,19 @@ is_valid_constexpr_fn (tree fun, bool complain, bool defer_ok)
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)
- error ("enclosing class of %q+#D is not a literal type", 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)
- {
- 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
declaration. Otherwise return NULL. Issue appropriate diagnostics
if necessary. Note that we only check the declaration, not the body
@@ -5507,23 +5465,13 @@ check_deferred_constexpr_decls (void)
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;
- valid = 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)
+ if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INFO (fun)))
{
DECL_DECLARED_CONSTEXPR_P (fun) = false;
return NULL;
@@ -5768,9 +5716,6 @@ register_constexpr_fundef (tree fun, tree body)
constexpr_fundef entry;
constexpr_fundef **slot;
- gcc_assert (DECL_DECLARED_CONSTEXPR_P (fun)
- && !DECL_DEFERRED_CONSTEXPR_CHECK (fun));
-
if (DECL_CONSTRUCTOR_P (fun))
body = build_constexpr_constructor_member_initializers
(DECL_CONTEXT (fun), body);
@@ -6143,7 +6088,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, /*defer_ok=*/false);
+ is_valid_constexpr_fn (fun, true);
}
*non_constant_p = true;
return t;
@@ -1,4 +1,4 @@
-// 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.
// { dg-options -std=c++0x }
@@ -28,4 +28,4 @@ struct D
C<D> c;
};
-constexpr D d {}; // { dg-error "not literal" }
+constexpr D d {}; // { dg-error "not a constexpr function" }
new file mode 100644
@@ -0,0 +1,12 @@
+// 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; }
struct Y
{
Y() { }
- constexpr Y f(Y y); // { dg-error "constexpr" }
- static constexpr Y g(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" }
};